347 lines
10 KiB
TypeScript
347 lines
10 KiB
TypeScript
/**
|
||
* 在有用户笔记的节点插入系统笔记
|
||
* 插入10条系统笔记到有用户笔记的节点
|
||
*/
|
||
|
||
import prisma from '../src/utils/prisma';
|
||
import { SYSTEM_USER_ID } from '../src/constants';
|
||
import { logger } from '../src/utils/logger';
|
||
|
||
/**
|
||
* 确保系统用户存在
|
||
*/
|
||
async function ensureSystemUser() {
|
||
const existingUser = await prisma.user.findUnique({
|
||
where: { id: SYSTEM_USER_ID },
|
||
});
|
||
|
||
if (existingUser) {
|
||
logger.info('系统用户已存在');
|
||
return existingUser;
|
||
}
|
||
|
||
const systemUser = await prisma.user.create({
|
||
data: {
|
||
id: SYSTEM_USER_ID,
|
||
nickname: '系统',
|
||
agreementAccepted: true,
|
||
},
|
||
});
|
||
|
||
logger.info('系统用户创建成功');
|
||
return systemUser;
|
||
}
|
||
|
||
/**
|
||
* 查找有用户笔记的节点
|
||
*/
|
||
async function findNodesWithUserNotes() {
|
||
// 查找有用户笔记的节点(排除系统笔记)
|
||
const notesWithNodes = await prisma.note.findMany({
|
||
where: {
|
||
nodeId: { not: null },
|
||
userId: { not: SYSTEM_USER_ID }, // 只统计用户笔记
|
||
},
|
||
select: {
|
||
nodeId: true,
|
||
},
|
||
distinct: ['nodeId'],
|
||
take: 10, // 取前10个节点
|
||
});
|
||
|
||
const nodeIds = notesWithNodes
|
||
.map((item) => item.nodeId)
|
||
.filter((id): id is string => id !== null);
|
||
|
||
logger.info(`找到 ${nodeIds.length} 个有用户笔记的节点`);
|
||
|
||
if (nodeIds.length === 0) {
|
||
// 如果没有用户笔记,使用"高效沟通的艺术"课程的前两节
|
||
logger.info('没有找到用户笔记,使用"高效沟通的艺术"课程的前两节');
|
||
const courseId = 'course_vertical_001';
|
||
const node1Id = 'node_vertical_001_01';
|
||
const node2Id = 'node_vertical_001_02';
|
||
|
||
const nodes = await prisma.courseNode.findMany({
|
||
where: {
|
||
id: { in: [node1Id, node2Id] },
|
||
},
|
||
include: {
|
||
course: {
|
||
select: {
|
||
id: true,
|
||
title: true,
|
||
},
|
||
},
|
||
},
|
||
});
|
||
|
||
return nodes;
|
||
}
|
||
|
||
// 获取节点详情
|
||
const nodes = await prisma.courseNode.findMany({
|
||
where: {
|
||
id: { in: nodeIds },
|
||
},
|
||
include: {
|
||
course: {
|
||
select: {
|
||
id: true,
|
||
title: true,
|
||
},
|
||
},
|
||
},
|
||
});
|
||
|
||
return nodes;
|
||
}
|
||
|
||
/**
|
||
* 创建系统笔记
|
||
*/
|
||
async function createSystemNote(data: {
|
||
nodeId: string;
|
||
courseId: string;
|
||
startIndex: number;
|
||
length: number;
|
||
type: 'highlight' | 'thought';
|
||
content?: string;
|
||
quotedText: string;
|
||
}) {
|
||
// 检查是否已存在相同的系统笔记(避免重复创建)
|
||
const existing = await prisma.note.findFirst({
|
||
where: {
|
||
userId: SYSTEM_USER_ID,
|
||
nodeId: data.nodeId,
|
||
startIndex: data.startIndex,
|
||
length: data.length,
|
||
type: data.type,
|
||
},
|
||
});
|
||
|
||
if (existing) {
|
||
logger.info(`系统笔记已存在: ${data.quotedText.substring(0, 20)}...`);
|
||
return existing;
|
||
}
|
||
|
||
const note = await prisma.note.create({
|
||
data: {
|
||
userId: SYSTEM_USER_ID,
|
||
courseId: data.courseId,
|
||
nodeId: data.nodeId,
|
||
startIndex: data.startIndex,
|
||
length: data.length,
|
||
type: data.type,
|
||
content: data.content || '',
|
||
quotedText: data.quotedText,
|
||
},
|
||
});
|
||
|
||
logger.info(`系统笔记创建成功: ${data.quotedText.substring(0, 20)}...`);
|
||
return note;
|
||
}
|
||
|
||
/**
|
||
* 主函数
|
||
*/
|
||
async function main() {
|
||
try {
|
||
logger.info('开始在有用户笔记的节点插入系统笔记...');
|
||
|
||
// 1. 确保系统用户存在
|
||
await ensureSystemUser();
|
||
|
||
// 2. 查找有用户笔记的节点
|
||
const nodes = await findNodesWithUserNotes();
|
||
|
||
if (nodes.length === 0) {
|
||
logger.info('没有找到有用户笔记的节点');
|
||
return;
|
||
}
|
||
|
||
// 3. 为每个节点创建系统笔记
|
||
let createdCount = 0;
|
||
const targetCount = 10;
|
||
|
||
for (const node of nodes) {
|
||
if (createdCount >= targetCount) {
|
||
break;
|
||
}
|
||
|
||
logger.info(`为节点 "${node.title}" 创建系统笔记...`);
|
||
|
||
// 获取该节点的用户笔记,用于生成系统笔记的位置
|
||
const userNotes = await prisma.note.findMany({
|
||
where: {
|
||
nodeId: node.id,
|
||
userId: { not: SYSTEM_USER_ID },
|
||
},
|
||
orderBy: { createdAt: 'asc' },
|
||
take: 5, // 每个节点最多创建5条系统笔记
|
||
});
|
||
|
||
logger.info(`节点 "${node.title}" 有 ${userNotes.length} 条用户笔记`);
|
||
|
||
// 获取该节点的现有系统笔记,用于创建重叠的笔记
|
||
const existingSystemNotes = await prisma.note.findMany({
|
||
where: {
|
||
nodeId: node.id,
|
||
userId: SYSTEM_USER_ID,
|
||
},
|
||
orderBy: { createdAt: 'asc' },
|
||
take: 10,
|
||
});
|
||
|
||
logger.info(`节点 "${node.title}" 现有 ${existingSystemNotes.length} 条系统笔记`);
|
||
|
||
// 为现有系统笔记创建重叠的笔记(如果有有效的startIndex)
|
||
for (const existingNote of existingSystemNotes) {
|
||
if (createdCount >= targetCount) {
|
||
break;
|
||
}
|
||
|
||
if (existingNote.startIndex === null || existingNote.length === null) {
|
||
continue; // 跳过无效的笔记
|
||
}
|
||
|
||
// 如果 startIndex 是 0,说明是测试数据,跳过
|
||
if (existingNote.startIndex === 0) {
|
||
continue;
|
||
}
|
||
|
||
// 创建与现有系统笔记部分重叠的新系统笔记
|
||
const overlapStart = existingNote.startIndex + Math.floor(existingNote.length / 2);
|
||
const systemNoteLength = Math.max(15, existingNote.length);
|
||
const systemNoteQuotedText = existingNote.quotedText
|
||
? `${existingNote.quotedText.substring(Math.floor(existingNote.quotedText.length / 2))}(系统补充)`
|
||
: '系统笔记内容(重叠测试)';
|
||
|
||
const type = existingNote.type === 'highlight' ? 'thought' : 'highlight';
|
||
const content =
|
||
type === 'thought'
|
||
? '这是一个系统笔记,用于测试重叠显示逻辑。当与用户笔记重叠时,只显示用户笔记的线段。'
|
||
: undefined;
|
||
|
||
await createSystemNote({
|
||
nodeId: node.id,
|
||
courseId: node.courseId,
|
||
startIndex: overlapStart,
|
||
length: systemNoteLength,
|
||
type,
|
||
content,
|
||
quotedText: systemNoteQuotedText,
|
||
});
|
||
|
||
createdCount++;
|
||
}
|
||
|
||
// 如果有用户笔记,为每个用户笔记创建系统笔记(部分重叠,部分不重叠)
|
||
if (userNotes.length > 0) {
|
||
// 有用户笔记的情况:为每个用户笔记创建系统笔记(部分重叠,部分不重叠)
|
||
for (let i = 0; i < userNotes.length && createdCount < targetCount; i++) {
|
||
const userNote = userNotes[i];
|
||
|
||
if (!userNote.startIndex || !userNote.length) {
|
||
continue;
|
||
}
|
||
|
||
// 策略1:创建与用户笔记部分重叠的系统笔记(用于测试重叠逻辑)
|
||
if (i % 2 === 0 && createdCount < targetCount) {
|
||
// 重叠情况:系统笔记从用户笔记中间开始,延伸到后面
|
||
const overlapStart = userNote.startIndex + Math.floor(userNote.length / 2);
|
||
const systemNoteLength = Math.max(15, userNote.length);
|
||
const systemNoteQuotedText = userNote.quotedText
|
||
? `${userNote.quotedText.substring(Math.floor(userNote.quotedText.length / 2))}(系统补充)`
|
||
: '系统笔记内容(重叠测试)';
|
||
|
||
const type = 'highlight';
|
||
await createSystemNote({
|
||
nodeId: node.id,
|
||
courseId: node.courseId,
|
||
startIndex: overlapStart,
|
||
length: systemNoteLength,
|
||
type,
|
||
quotedText: systemNoteQuotedText,
|
||
});
|
||
|
||
createdCount++;
|
||
}
|
||
|
||
// 策略2:创建不重叠的系统笔记(在用户笔记前面或后面)
|
||
if (createdCount < targetCount) {
|
||
// 在用户笔记前面创建系统笔记
|
||
const beforeStartIndex = Math.max(0, userNote.startIndex - 30);
|
||
const beforeLength = Math.min(20, userNote.startIndex - beforeStartIndex);
|
||
|
||
if (beforeLength > 5) {
|
||
const systemNoteQuotedText = '系统笔记:这是不重叠的部分';
|
||
const type = Math.random() > 0.5 ? 'thought' : 'highlight';
|
||
const content =
|
||
type === 'thought'
|
||
? '这是一个系统笔记,用于测试非重叠显示逻辑。'
|
||
: undefined;
|
||
|
||
await createSystemNote({
|
||
nodeId: node.id,
|
||
courseId: node.courseId,
|
||
startIndex: beforeStartIndex,
|
||
length: beforeLength,
|
||
type,
|
||
content,
|
||
quotedText: systemNoteQuotedText,
|
||
});
|
||
|
||
createdCount++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// ✅ 如果还不够10条,直接创建系统笔记(不依赖现有笔记)
|
||
const notesPerNode = Math.ceil(targetCount / nodes.length);
|
||
const remainingCount = Math.min(notesPerNode, targetCount - createdCount);
|
||
|
||
for (let i = 0; i < remainingCount && createdCount < targetCount; i++) {
|
||
const startIndex = 100 + i * 50; // 每个笔记间隔50个字符,从100开始
|
||
const length = 20;
|
||
const systemNoteQuotedText = `系统笔记 ${createdCount + 1}:这是不重叠的部分`;
|
||
const type = createdCount % 2 === 0 ? 'thought' : 'highlight';
|
||
const content =
|
||
type === 'thought'
|
||
? `系统想法笔记 ${createdCount + 1}:这是一个系统笔记,用于测试非重叠显示逻辑。`
|
||
: undefined;
|
||
|
||
await createSystemNote({
|
||
nodeId: node.id,
|
||
courseId: node.courseId,
|
||
startIndex,
|
||
length,
|
||
type,
|
||
content,
|
||
quotedText: systemNoteQuotedText,
|
||
});
|
||
|
||
createdCount++;
|
||
}
|
||
}
|
||
|
||
logger.info(`系统笔记创建完成!共创建 ${createdCount} 条系统笔记`);
|
||
} catch (error) {
|
||
logger.error('创建系统笔记失败:', error);
|
||
throw error;
|
||
} finally {
|
||
await prisma.$disconnect();
|
||
}
|
||
}
|
||
|
||
// 运行脚本
|
||
main()
|
||
.then(() => {
|
||
process.exit(0);
|
||
})
|
||
.catch((error) => {
|
||
console.error(error);
|
||
process.exit(1);
|
||
});
|