migrate-genstage.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /**
  2. * 数据迁移脚本:将旧字段迁移到新的 genStage 字段
  3. * Run: npx ts-node prisma/migrate-genstage.ts
  4. */
  5. import { PrismaClient } from '@prisma/client';
  6. const prisma = new PrismaClient();
  7. async function migrate() {
  8. console.log('开始数据迁移...');
  9. // ========== Book 迁移 ==========
  10. console.log('\n迁移 Book 表...');
  11. const books = await prisma.book.findMany();
  12. let updatedBookCount = 0;
  13. for (const book of books) {
  14. let newGenStage: string;
  15. switch (book.status) {
  16. case 'draft':
  17. newGenStage = 'draft';
  18. break;
  19. case 'planning':
  20. newGenStage = 'outline_completed';
  21. break;
  22. case 'generating':
  23. // 需要检查子章节的实际状态
  24. newGenStage = await inferBookGenStageFromChapters(book.id);
  25. break;
  26. case 'completed':
  27. newGenStage = await inferBookGenStageFromChapters(book.id);
  28. break;
  29. case 'failed':
  30. case 'interrupted':
  31. newGenStage = 'failed';
  32. break;
  33. default:
  34. newGenStage = 'draft';
  35. }
  36. await prisma.book.update({
  37. where: { id: book.id },
  38. data: {
  39. genStage: newGenStage,
  40. failedStage: newGenStage === 'failed' ? book.status : undefined,
  41. },
  42. });
  43. updatedBookCount++;
  44. console.log(` Book ${book.id}: ${book.status} → ${newGenStage}`);
  45. }
  46. console.log(`Book 迁移完成: ${updatedBookCount} 条`);
  47. // ========== BookChapter 迁移 ==========
  48. console.log('\n迁移 BookChapter 表...');
  49. const chapters = await prisma.bookChapter.findMany();
  50. let updatedChapterCount = 0;
  51. for (const chapter of chapters) {
  52. let newGenStage: string;
  53. if (chapter.videoStatus === 'completed') {
  54. newGenStage = 'video_completed';
  55. } else if (chapter.videoStatus === 'generating') {
  56. newGenStage = 'video_generating';
  57. } else if (chapter.audioStatus === 'completed') {
  58. newGenStage = 'audio_completed';
  59. } else if (chapter.audioStatus === 'generating') {
  60. newGenStage = 'audio_generating';
  61. } else if (chapter.contentStatus === 'completed') {
  62. newGenStage = 'content_completed';
  63. } else if (chapter.contentStatus === 'generating') {
  64. newGenStage = 'content_generating';
  65. } else if (chapter.status === 'completed') {
  66. // 旧数据只有 status
  67. newGenStage = 'content_completed';
  68. } else if (chapter.status === 'failed' || chapter.contentStatus === 'failed' || chapter.audioStatus === 'failed' || chapter.videoStatus === 'failed') {
  69. newGenStage = 'failed';
  70. } else {
  71. newGenStage = 'idle';
  72. }
  73. await prisma.bookChapter.update({
  74. where: { id: chapter.id },
  75. data: { genStage: newGenStage },
  76. });
  77. updatedChapterCount++;
  78. console.log(` Chapter ${chapter.id}: status=${chapter.status}, content=${chapter.contentStatus}, audio=${chapter.audioStatus}, video=${chapter.videoStatus} → ${newGenStage}`);
  79. }
  80. console.log(`BookChapter 迁移完成: ${updatedChapterCount} 条`);
  81. console.log('\n✅ 数据迁移完成!');
  82. }
  83. /**
  84. * 根据子章节状态推断 Book 的 genStage
  85. */
  86. async function inferBookGenStageFromChapters(bookId: number): Promise<string> {
  87. const chapters = await prisma.bookChapter.findMany({
  88. where: { bookId, level: { gte: 1 }, parentId: 0 },
  89. });
  90. if (chapters.length === 0) return 'draft';
  91. // 检查是否有任意章节已达到 video_completed
  92. const hasVideoCompleted = chapters.some(c => c.genStage === 'video_completed' || c.videoStatus === 'completed');
  93. if (hasVideoCompleted) return 'video_completed';
  94. // 检查是否有章节已达到 audio_completed
  95. const hasAudioCompleted = chapters.some(c => c.genStage === 'audio_completed' || c.audioStatus === 'completed');
  96. if (hasAudioCompleted) return 'audio_completed';
  97. // 检查是否有章节已达到 content_completed
  98. const hasContentCompleted = chapters.some(c => c.genStage === 'content_completed' || c.contentStatus === 'completed');
  99. if (hasContentCompleted) return 'content_generating'; // 部分完成,仍在生成中
  100. return 'content_generating';
  101. }
  102. migrate()
  103. .catch(console.error)
  104. .finally(() => prisma.$disconnect());