/** * 脚本:为所有笔记本自动更新封面(从关联笔记的课程中获取) * ✅ 新增:支持通过课程名称匹配(处理历史数据问题) * * 使用方法: * npx ts-node scripts/update-notebook-covers.ts */ import prisma from '../src/utils/prisma'; // ✅ 辅助函数:从笔记本标题中提取课程名称(移除书名号) function extractCourseNameFromTitle(notebookTitle: string): string { // 移除书名号《》和多余的空格 return notebookTitle .replace(/《/g, '') .replace(/》/g, '') .trim(); } async function updateNotebookCovers() { try { console.log('🚀 开始更新笔记本封面...\n'); // 获取所有封面为空的笔记本 const notebooks = await prisma.notebook.findMany({ where: { OR: [ { coverImage: null }, { coverImage: '' }, ], }, include: { _count: { select: { notes: true }, }, }, }); console.log(`📚 找到 ${notebooks.length} 个需要更新封面的笔记本\n`); let updatedCount = 0; let skippedCount = 0; for (const notebook of notebooks) { console.log(`📖 处理笔记本: ${notebook.title} (ID: ${notebook.id})`); console.log(` - 当前封面: ${notebook.coverImage || 'null'}`); console.log(` - 笔记数量: ${notebook._count.notes}`); let coverImage: string | null = null; let source = ''; // 方法1:查找该笔记本的第一个有课程关联的笔记 const firstNote = await prisma.note.findFirst({ where: { notebookId: notebook.id, courseId: { not: null }, }, orderBy: { createdAt: 'asc' }, include: { course: { select: { id: true, title: true, coverImage: true, }, }, }, }); if (firstNote?.course?.coverImage) { // ✅ 方法1成功:从笔记关联的课程获取封面 coverImage = firstNote.course.coverImage; source = `笔记关联的课程: ${firstNote.course.title} (ID: ${firstNote.course.id})`; } else if (firstNote?.courseId) { // 笔记有 courseId,但课程没有封面(单独查询) const course = await prisma.course.findUnique({ where: { id: firstNote.courseId }, select: { coverImage: true, title: true }, }); if (course?.coverImage) { coverImage = course.coverImage; source = `课程查询: ${course.title || firstNote.courseId}`; } } // ✅ 方法2:如果方法1失败,尝试通过课程名称匹配(处理历史数据) if (!coverImage && notebook._count.notes > 0) { const courseName = extractCourseNameFromTitle(notebook.title); console.log(` 🔍 尝试通过课程名称匹配: "${courseName}"`); // 查找匹配的课程(标题包含课程名称) const matchingCourse = await prisma.course.findFirst({ where: { title: { contains: courseName, }, coverImage: { not: null }, }, select: { id: true, title: true, coverImage: true, }, }); if (matchingCourse?.coverImage) { coverImage = matchingCourse.coverImage; source = `课程名称匹配: ${matchingCourse.title} (ID: ${matchingCourse.id})`; console.log(` ✅ 找到匹配的课程: ${matchingCourse.title}`); } } // 更新笔记本封面 if (coverImage) { await prisma.notebook.update({ where: { id: notebook.id }, data: { coverImage }, }); console.log(` ✅ 成功更新封面: ${coverImage}`); console.log(` 📘 来源: ${source}\n`); updatedCount++; } else { // 无法获取封面 const noteCount = await prisma.note.count({ where: { notebookId: notebook.id }, }); const noteWithCourseId = await prisma.note.count({ where: { notebookId: notebook.id, courseId: { not: null }, }, }); if (noteCount > 0) { console.log(` ⚠️ 有 ${noteCount} 条笔记,其中 ${noteWithCourseId} 条有 courseId,但无法获取封面\n`); } else { console.log(` ⚠️ 没有笔记\n`); } skippedCount++; } } console.log('\n📊 更新完成:'); console.log(` ✅ 成功更新: ${updatedCount} 个`); console.log(` ⚠️ 跳过: ${skippedCount} 个`); } catch (error) { console.error('❌ 更新失败:', error); throw error; } finally { await prisma.$disconnect(); } } // 执行更新 updateNotebookCovers() .then(() => { console.log('\n✅ 脚本执行完成'); process.exit(0); }) .catch((error) => { console.error('\n❌ 脚本执行失败:', error); process.exit(1); });