diff --git a/frontend-web/src/open-canvas/components/ai-writing/AIWritingPanel.tsx b/frontend-web/src/open-canvas/components/ai-writing/AIWritingPanel.tsx index 92d4adb8..660afe01 100644 --- a/frontend-web/src/open-canvas/components/ai-writing/AIWritingPanel.tsx +++ b/frontend-web/src/open-canvas/components/ai-writing/AIWritingPanel.tsx @@ -4,6 +4,13 @@ import { ChevronsDown, Play, Plus, RotateCcw, Settings2, Square } from 'lucide-r import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; +import { useArticleTypes } from '../../hooks/useArticleTypes'; import { useCanvasGraphContext } from '../../contexts/CanvasGraphContext'; import { useAIWriting } from '../../hooks/useAIWriting'; @@ -40,9 +47,13 @@ export function AIWritingPanel() { const { setArtifact } = useCanvasGraphContext(); const { state, startWriting, submitIntervention, pauseWriting, resumeWriting, reset } = useAIWriting(); const { sessions, loading: sessionsLoading, refresh, rename, remove } = useAIWritingSessions(); + const { articleTypes, refresh: refreshArticleTypes } = useArticleTypes(); + + useEffect(() => { refreshArticleTypes(); }, [refreshArticleTypes]); // History view state — null means normal writing mode const [historySession, setHistorySession] = useState(null); + const [reqDialogOpen, setReqDialogOpen] = useState(false); const isIdle = state.status === 'idle'; const isDone = state.status === 'done'; @@ -203,7 +214,15 @@ export function AIWritingPanel() {
{/* 头部 */}
- AI 智能写作 + { if (!isIdle && state.request) setReqDialogOpen(true); }} + > + AI 智能写作 +
+ ); +} + +function ReqRow({ label, children }: { label: string; children: React.ReactNode }) { + return ( +
+

{label}

+ {children}
); } diff --git a/frontend-web/src/open-canvas/components/ai-writing/InterventionCard.tsx b/frontend-web/src/open-canvas/components/ai-writing/InterventionCard.tsx index 65526f27..48738c37 100644 --- a/frontend-web/src/open-canvas/components/ai-writing/InterventionCard.tsx +++ b/frontend-web/src/open-canvas/components/ai-writing/InterventionCard.tsx @@ -1,7 +1,7 @@ -import { useState } from 'react'; +import { useRef, useState } from 'react'; import { PauseCircle, CheckCircle2, RotateCcw, Search, - RefreshCw, PenLine, ArrowRight, ShieldAlert, ClipboardEdit, + RefreshCw, PenLine, ArrowRight, ShieldAlert, ClipboardEdit, SendHorizonal, } from 'lucide-react'; import { Button } from '@/components/ui/button'; import type { @@ -222,9 +222,9 @@ interface OutlineConfirmCardProps { function OutlineConfirmCard({ outline: initialOutline, onSubmit, disabled }: OutlineConfirmCardProps) { const [editedOutline, setEditedOutline] = useState(initialOutline); - const [showReplan, setShowReplan] = useState(false); const [feedback, setFeedback] = useState(''); const [submitting, setSubmitting] = useState(false); + const textareaRef = useRef(null); async function handleConfirm() { setSubmitting(true); @@ -236,11 +236,28 @@ function OutlineConfirmCard({ outline: initialOutline, onSubmit, disabled }: Out } async function handleReplan() { + const text = feedback.trim(); + if (!text) return; setSubmitting(true); - await onSubmit({ action: 're_outline', outlineFeedback: feedback.trim() }); + await onSubmit({ action: 're_outline', outlineFeedback: text }); setSubmitting(false); } + function handleKeyDown(e: React.KeyboardEvent) { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + handleReplan(); + } + } + + // 自动调整高度 + function handleInput(e: React.ChangeEvent) { + setFeedback(e.target.value); + const el = e.target; + el.style.height = 'auto'; + el.style.height = `${el.scrollHeight}px`; + } + return (
@@ -248,7 +265,7 @@ function OutlineConfirmCard({ outline: initialOutline, onSubmit, disabled }: Out

请确认大纲后继续写作

- 可直接点击章节标题或要点进行编辑,或要求重新规划大纲。 + 可直接点击章节标题或要点进行编辑,或在下方输入意见让 AI 重新规划。

@@ -257,40 +274,37 @@ function OutlineConfirmCard({ outline: initialOutline, onSubmit, disabled }: Out ? :

大纲加载中…

} - {showReplan && ( -
- -