125 lines
3.8 KiB
TypeScript
125 lines
3.8 KiB
TypeScript
|
|
import { PrismaClient } from '@prisma/client';
|
|||
|
|
import { logger } from '../src/utils/logger';
|
|||
|
|
|
|||
|
|
const prisma = new PrismaClient();
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 数据清洗脚本:为所有没有封面的笔记本自动补上相关课程的封面
|
|||
|
|
*/
|
|||
|
|
async function backfillNotebooksCover() {
|
|||
|
|
try {
|
|||
|
|
console.log('=== 开始清洗笔记本封面数据 ===\n');
|
|||
|
|
|
|||
|
|
// 获取所有没有封面的笔记本
|
|||
|
|
const notebooks = await prisma.notebook.findMany({
|
|||
|
|
where: {
|
|||
|
|
OR: [
|
|||
|
|
{ coverImage: null },
|
|||
|
|
{ coverImage: '' },
|
|||
|
|
],
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
console.log(`找到 ${notebooks.length} 个需要补封面的笔记本\n`);
|
|||
|
|
|
|||
|
|
let successCount = 0;
|
|||
|
|
let failCount = 0;
|
|||
|
|
|
|||
|
|
for (const notebook of notebooks) {
|
|||
|
|
let coverImage: string | null = null;
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 方法1:从关联笔记的课程中获取
|
|||
|
|
const firstNote = await prisma.note.findFirst({
|
|||
|
|
where: {
|
|||
|
|
notebookId: notebook.id,
|
|||
|
|
courseId: { not: null },
|
|||
|
|
},
|
|||
|
|
orderBy: { createdAt: 'asc' },
|
|||
|
|
include: {
|
|||
|
|
course: {
|
|||
|
|
select: {
|
|||
|
|
coverImage: true,
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (firstNote?.course?.coverImage) {
|
|||
|
|
coverImage = firstNote.course.coverImage;
|
|||
|
|
console.log(`✅ [${notebook.id}] 从关联笔记的课程获取封面: ${coverImage}`);
|
|||
|
|
} else if (firstNote?.courseId) {
|
|||
|
|
// 备用方案:单独查询课程
|
|||
|
|
const course = await prisma.course.findUnique({
|
|||
|
|
where: { id: firstNote.courseId },
|
|||
|
|
select: { coverImage: true },
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (course?.coverImage) {
|
|||
|
|
coverImage = course.coverImage;
|
|||
|
|
console.log(`✅ [${notebook.id}] 从课程 ${firstNote.courseId} 获取封面(备用方案): ${coverImage}`);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 方法2:如果方法1失败,通过课程名称匹配
|
|||
|
|
if (!coverImage) {
|
|||
|
|
const courseName = notebook.title
|
|||
|
|
.replace(/《/g, '')
|
|||
|
|
.replace(/》/g, '')
|
|||
|
|
.trim();
|
|||
|
|
|
|||
|
|
if (courseName) {
|
|||
|
|
// 先尝试精确匹配
|
|||
|
|
let matchingCourse = await prisma.course.findFirst({
|
|||
|
|
where: { title: courseName },
|
|||
|
|
select: { id: true, title: true, coverImage: true },
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 如果精确匹配失败,尝试包含匹配
|
|||
|
|
if (!matchingCourse) {
|
|||
|
|
matchingCourse = await prisma.course.findFirst({
|
|||
|
|
where: {
|
|||
|
|
title: {
|
|||
|
|
contains: courseName,
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
select: { id: true, title: true, coverImage: true },
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (matchingCourse?.coverImage) {
|
|||
|
|
coverImage = matchingCourse.coverImage;
|
|||
|
|
console.log(`✅ [${notebook.id}] 通过课程名称匹配获取封面: ${matchingCourse.title} -> ${coverImage}`);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 更新笔记本封面
|
|||
|
|
if (coverImage) {
|
|||
|
|
await prisma.notebook.update({
|
|||
|
|
where: { id: notebook.id },
|
|||
|
|
data: { coverImage },
|
|||
|
|
});
|
|||
|
|
successCount++;
|
|||
|
|
} else {
|
|||
|
|
console.log(`⚠️ [${notebook.id}] "${notebook.title}" 无法找到匹配的课程封面`);
|
|||
|
|
failCount++;
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error(`❌ [${notebook.id}] 处理失败:`, error);
|
|||
|
|
failCount++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log(`\n=== 清洗完成 ===`);
|
|||
|
|
console.log(`成功: ${successCount} 个`);
|
|||
|
|
console.log(`失败: ${failCount} 个`);
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('脚本执行失败:', error);
|
|||
|
|
} finally {
|
|||
|
|
await prisma.$disconnect();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
backfillNotebooksCover();
|