import type { ArticleReadingConfig, ArticleReadingReport, ArticleReadingTask, } from '@/types/articleReading' import type { SpeakingRecommendationTask } from '@/types/englishSpeaking' export type SpeakingTaskFilter = 'all' | 'topic-discussion' | 'article-reading' export function buildEmptyArticleConfig(grade: string): ArticleReadingConfig { return { type: 'article', grade, title: '', content: '', practice: { mode: 'time', duration: 10 }, evaluation: { showReport: true }, } } export function buildArticleConfig(task: ArticleReadingTask, grade: string): ArticleReadingConfig { return { type: 'article', grade, title: task.titleEn, content: task.content, practice: { mode: 'time', duration: task.durationMinutes }, evaluation: { showReport: true }, } } export function filterSpeakingTasks( tasks: SpeakingRecommendationTask[], filter: SpeakingTaskFilter, ): SpeakingRecommendationTask[] { return filter === 'all' ? tasks : tasks.filter(task => task.taskType === filter) } export function scoreToStars(score: number | null | undefined): number { if (score == null) return 0 return Math.round(Math.min(100, Math.max(0, score)) * 5) / 100 } /** 最终报告一次性显示:无段落还在生成,且整篇总评已定局(spec §4.1)。 */ export function isFinalReportReady( report: Pick, ): boolean { return !report.paragraphs.some(paragraph => paragraph.status === 'generating') && (report.overallStatus === 'completed' || report.overallStatus === 'failed' || report.overallStatus === null) } export function pollDelayMs(attempt: number): number { return Math.min(8000, 1000 * 2 ** Math.max(0, attempt)) }