diff --git a/qwen3-tts-frontend/src/pages/Audiobook.tsx b/qwen3-tts-frontend/src/pages/Audiobook.tsx index 39cbd9e..7cb019b 100644 --- a/qwen3-tts-frontend/src/pages/Audiobook.tsx +++ b/qwen3-tts-frontend/src/pages/Audiobook.tsx @@ -142,7 +142,7 @@ function SequentialPlayer({ function LogStream({ projectId, active }: { projectId: number; active: boolean }) { const [lines, setLines] = useState([]) const [done, setDone] = useState(false) - const bottomRef = useRef(null) + const containerRef = useRef(null) const activeRef = useRef(active) activeRef.current = active @@ -192,20 +192,20 @@ function LogStream({ projectId, active }: { projectId: number; active: boolean } }, [projectId, active]) useEffect(() => { - bottomRef.current?.scrollIntoView({ behavior: 'smooth' }) + const el = containerRef.current + if (el) el.scrollTop = el.scrollHeight }, [lines]) if (lines.length === 0) return null return ( -
+
{lines.map((line, i) => (
{line}
))} {!done && ( )} -
) } @@ -429,6 +429,29 @@ function ProjectCard({ project, onRefresh }: { project: AudiobookProject; onRefr } } + const handleProcessAll = async () => { + if (!detail) return + setLoadingAction(true) + setIsPolling(true) + try { + const pending = detail.chapters.filter(c => c.status === 'pending' || c.status === 'error') + const ready = detail.chapters.filter(c => c.status === 'ready') + await Promise.all([ + ...pending.map(c => audiobookApi.parseChapter(project.id, c.id)), + ...ready.map(c => audiobookApi.generate(project.id, c.chapter_index)), + ]) + toast.success('全部任务已触发') + onRefresh() + fetchDetail() + fetchSegments() + } catch (e: any) { + setIsPolling(false) + toast.error(formatApiError(e)) + } finally { + setLoadingAction(false) + } + } + const handleDownload = async (chapterIndex?: number) => { setLoadingAction(true) try { @@ -622,8 +645,20 @@ function ProjectCard({ project, onRefresh }: { project: AudiobookProject; onRefr {detail && detail.chapters.length > 0 && ['ready', 'generating', 'done'].includes(status) && (
-
- 章节列表(共 {detail.chapters.length} 章) +
+
+ 章节列表(共 {detail.chapters.length} 章) +
+ {detail.chapters.some(c => ['pending', 'error', 'ready'].includes(c.status)) && ( + + )}
{detail.chapters.map(ch => {