'use client'; import React, { useEffect, useMemo, useRef, useState } from 'react'; import Link from 'next/link'; import { useParams } from 'next/navigation'; import { ArrowLeft, Check, Loader2, RefreshCw, Send, Settings2 } from 'lucide-react'; import { getNotification, sendMessage } from '@/lib/api'; import type { ChatMessage, NotificationDetail } from '@/types'; import { pickAppText } from '@/lib/i18n/core'; import { useAppI18n } from '@/lib/i18n/provider'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { ChatWorkbench } from '@/components/chat-workbench/ChatWorkbench'; type ReplyIntent = 'revise_once' | 'update_future'; export default function NotificationDetailPage() { const { locale } = useAppI18n(); const params = useParams<{ scheduledRunId: string }>(); const scheduledRunId = decodeURIComponent(params.scheduledRunId); const [detail, setDetail] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [intent, setIntent] = useState(null); const [input, setInput] = useState(''); const [submitting, setSubmitting] = useState(false); const messagesEndRef = useRef(null); const viewportRef = useRef(null); const load = React.useCallback(async () => { setLoading(true); setError(null); try { setDetail(await getNotification(scheduledRunId)); } catch (err: any) { setError(err.message || pickAppText(locale, '加载通知详情失败', 'Failed to load notification detail')); } finally { setLoading(false); } }, [locale, scheduledRunId]); useEffect(() => { void load(); }, [load]); const messages = useMemo(() => { if (!detail) return []; const runId = detail.run_id; const scoped = detail.detail.messages.filter((message) => !runId || message.run_id === runId || message.scheduled_run_id === detail.scheduled_run_id); if (scoped.length > 0) return scoped; return [ { role: 'user', content: detail.message, timestamp: detail.started_at || undefined }, { role: 'assistant', content: detail.output || detail.error || '', timestamp: detail.finished_at || detail.started_at || undefined, run_id: detail.run_id || undefined, task_id: detail.task_id || null }, ]; }, [detail]); const formatTime = (value?: string | null) => { if (!value) return '-'; return new Date(value).toLocaleString(locale); }; const submitReply = async () => { if (!detail || !intent || !input.trim() || submitting) return; setSubmitting(true); setError(null); try { await sendMessage( input.trim(), detail.notification_session_id, undefined, { replyToScheduledRunId: detail.scheduled_run_id, scheduledReplyIntent: intent, } ); setInput(''); await load(); } catch (err: any) { setError(err.message || pickAppText(locale, '提交修改失败', 'Failed to submit revision')); } finally { setSubmitting(false); } }; if (loading) { return (
{pickAppText(locale, '加载中', 'Loading')}
); } if (!detail) { return (
{pickAppText(locale, '返回通知', 'Back to notifications')}

{error || pickAppText(locale, '通知不存在', 'Notification not found')}

); } return (
{pickAppText(locale, '通知列表', 'Notifications')}

{detail.title || detail.job_name}

{detail.status} {detail.engaged && {pickAppText(locale, '已接入 Task', 'Task linked')}}

{pickAppText(locale, '生成时间', 'Generated')}: {formatTime(detail.started_at)}

{detail.task_id && ( )}
{error &&
{error}
}
{}} onFeedback={() => {}} />
{detail.engaged && ( {pickAppText(locale, '这条通知已经接入 Task', 'This notification is linked to a Task')} )}
{intent && (