'use client' import type { FC } from 'react' import { useState } from 'react' import { RiCalendarScheduleLine, RiTimeLine } from '@remixicon/react' import Modal from '@/app/components/base/modal' import Button from '@/app/components/base/button' import { ScheduleAction } from '@/models/document-schedule' import type { CreateScheduleRequest } from '@/models/document-schedule' import { useCreateSchedule } from '@/service/knowledge/use-document-schedule' import { useToastContext } from '@/app/components/base/toast' import { useQueryClient } from '@tanstack/react-query' import { useScheduleListKey } from '@/service/knowledge/use-document-schedule' type ScheduleModalProps = { isOpen: boolean onClose: () => void datasetId: string documentId: string documentName: string } const ScheduleModal: FC = ({ isOpen, onClose, datasetId, documentId, documentName, }) => { const { notify } = useToastContext() const queryClient = useQueryClient() const [action, setAction] = useState(ScheduleAction.ENABLE) const [scheduledDate, setScheduledDate] = useState('') const [scheduledTime, setScheduledTime] = useState('') const [reason, setReason] = useState('') const [notes, setNotes] = useState('') const { mutateAsync: createSchedule, isPending } = useCreateSchedule() const handleSubmit = async () => { if (!scheduledDate || !scheduledTime) { notify({ type: 'error', message: '请选择日期和时间' }) return } // Combine date and time to ISO format const scheduledAt = new Date(`${scheduledDate}T${scheduledTime}`).toISOString() // Validate future time if (new Date(scheduledAt) <= new Date()) { notify({ type: 'error', message: '定时时间必须在未来' }) return } const body: CreateScheduleRequest = { action, scheduled_at: scheduledAt, metadata: { reason: reason || undefined, notes: notes || undefined, }, } try { await createSchedule({ datasetId, documentId, body, }) notify({ type: 'success', message: '定时任务创建成功', }) // Invalidate schedules query queryClient.invalidateQueries({ queryKey: useScheduleListKey(datasetId, documentId), }) handleClose() } catch (error: any) { notify({ type: 'error', message: error.message || '定时任务创建失败', }) } } const handleClose = () => { setAction(ScheduleAction.ENABLE) setScheduledDate('') setScheduledTime('') setReason('') setNotes('') onClose() } // Get tomorrow's date as minimum const getTomorrowDate = () => { const tomorrow = new Date() tomorrow.setDate(tomorrow.getDate() + 1) return tomorrow.toISOString().split('T')[0] } const getActionLabel = (actionType: ScheduleAction) => { const labels = { [ScheduleAction.ENABLE]: '启用', [ScheduleAction.DISABLE]: '禁用', [ScheduleAction.ARCHIVE]: '归档', } return labels[actionType] } return ( 创建定时任务 } className="!w-[540px]" >
{/* Document Name */}
{documentName}
{/* Action Selection */}
{[ { value: ScheduleAction.ENABLE, label: '启用' }, { value: ScheduleAction.DISABLE, label: '禁用' }, { value: ScheduleAction.ARCHIVE, label: '归档' }, ].map(option => ( ))}
{/* Scheduled Date & Time */}
setScheduledDate(e.target.value)} min={getTomorrowDate()} className="w-full px-3 py-2 bg-components-input-bg-normal border border-components-input-border-active rounded-lg text-sm text-text-primary placeholder:text-text-quaternary focus:outline-none focus:ring-1 focus:ring-components-input-border-active" />
setScheduledTime(e.target.value)} className="w-full px-3 py-2 bg-components-input-bg-normal border border-components-input-border-active rounded-lg text-sm text-text-primary placeholder:text-text-quaternary focus:outline-none focus:ring-1 focus:ring-components-input-border-active" />
{/* Reason (Optional) */}
setReason(e.target.value)} placeholder="例如:每月内容更新" maxLength={100} className="w-full px-3 py-2 bg-components-input-bg-normal border border-components-input-border-active rounded-lg text-sm text-text-primary placeholder:text-text-quaternary focus:outline-none focus:ring-1 focus:ring-components-input-border-active" />
{/* Notes (Optional) */}