From ff4135b7c6d4dfc10af038accd2d6fd6fbbe7398 Mon Sep 17 00:00:00 2001 From: wangdl Date: Fri, 19 Jun 2026 12:41:46 +0800 Subject: [PATCH] feat: add enrichWithNames to admin learning API All list endpoints now return userName, kbName, materialName resolved from User, KnowledgeBase, KnowledgeSource tables. Co-Authored-By: Claude Opus 4.7 --- .../admin-learning.service.ts | 49 ++++++++++++++++--- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/src/modules/learning-session/admin-learning.service.ts b/src/modules/learning-session/admin-learning.service.ts index d39e316..cb8b2bb 100644 --- a/src/modules/learning-session/admin-learning.service.ts +++ b/src/modules/learning-session/admin-learning.service.ts @@ -9,6 +9,39 @@ export class AdminLearningService { private readonly snapshotBuilder: SnapshotBuilderService, ) {} + // ══ Name resolution ══ + + private async enrichWithNames>(items: T[]): Promise<(T & { userName?: string; kbName?: string; materialName?: string })[]> { + if (items.length === 0) return items; + + const userIds = [...new Set(items.map(i => i.userId).filter(Boolean))]; + const kbIds = [...new Set(items.map(i => i.knowledgeBaseId).filter(Boolean))]; + const materialIds = [...new Set(items.map(i => i.materialId).filter(Boolean))]; + + const [users, kbs, materials] = await Promise.all([ + userIds.length > 0 + ? this.prisma.user.findMany({ where: { id: { in: userIds } }, select: { id: true, nickname: true } }) + : [], + kbIds.length > 0 + ? this.prisma.knowledgeBase.findMany({ where: { id: { in: kbIds } }, select: { id: true, title: true } }) + : [], + materialIds.length > 0 + ? this.prisma.knowledgeSource.findMany({ where: { id: { in: materialIds } }, select: { id: true, originalFilename: true, title: true } }) + : [], + ]); + + const userMap = new Map(users.map(u => [u.id, u.nickname || u.id] as [string, string])); + const kbMap = new Map(kbs.map(k => [k.id, k.title] as [string, string])); + const matMap = new Map(materials.map(m => [m.id, m.originalFilename || m.title || m.id] as [string, string])); + + return items.map(item => ({ + ...item, + userName: userMap.get(item.userId), + kbName: kbMap.get(item.knowledgeBaseId), + materialName: matMap.get(item.materialId), + })); + } + // ══ Knowledge Bases (for filter dropdown) ══ async getKnowledgeBases() { @@ -112,7 +145,7 @@ export class AdminLearningService { this.prisma.readingEvent.findMany({ where, orderBy, skip: (page - 1) * limit, take: limit }), this.prisma.readingEvent.count({ where }), ]); - return { items, total, page, limit }; + const enriched = await this.enrichWithNames(items); return { items: enriched, total, page, limit }; } async getReadingEvent(id: string) { @@ -138,7 +171,7 @@ export class AdminLearningService { this.prisma.learningSession.findMany({ where, orderBy: { startedAt: 'desc' }, skip: (page - 1) * limit, take: limit }), this.prisma.learningSession.count({ where }), ]); - return { items, total, page, limit }; + const enriched = await this.enrichWithNames(items); return { items: enriched, total, page, limit }; } async getSession(id: string) { @@ -161,7 +194,7 @@ export class AdminLearningService { this.prisma.materialReadingProgress.findMany({ where, orderBy: { lastReadAt: 'desc' }, skip: (page - 1) * limit, take: limit }), this.prisma.materialReadingProgress.count({ where }), ]); - return { items, total, page, limit }; + const enriched = await this.enrichWithNames(items); return { items: enriched, total, page, limit }; } async getProgressDetail(id: string) { @@ -184,7 +217,7 @@ export class AdminLearningService { this.prisma.dailyLearningActivity.findMany({ where, orderBy: { activityDate: 'desc' }, skip: (page - 1) * limit, take: limit }), this.prisma.dailyLearningActivity.count({ where }), ]); - return { items, total, page, limit }; + const enriched = await this.enrichWithNames(items); return { items: enriched, total, page, limit }; } // ══ Records ══ @@ -202,7 +235,7 @@ export class AdminLearningService { this.prisma.learningRecord.findMany({ where, orderBy: { occurredAt: 'desc' }, skip: (page - 1) * limit, take: limit }), this.prisma.learningRecord.count({ where }), ]); - return { items, total, page, limit }; + const enriched = await this.enrichWithNames(items); return { items: enriched, total, page, limit }; } async getRecord(id: string) { @@ -225,7 +258,7 @@ export class AdminLearningService { }), this.prisma.aiAnalysisResult.count({ where }), ]); - return { items, total, page, limit }; + const enriched = await this.enrichWithNames(items); return { items: enriched, total, page, limit }; } // ══ AI Usage ══ @@ -243,7 +276,7 @@ export class AdminLearningService { }), this.prisma.aiUsageLog.count({ where }), ]); - return { items, total, page, limit }; + const enriched = await this.enrichWithNames(items); return { items: enriched, total, page, limit }; } // ══ Timeline ══ @@ -310,7 +343,7 @@ export class AdminLearningService { this.prisma.temporaryReadingMaterial.findMany({ orderBy: { createdAt: 'desc' }, skip: (page - 1) * limit, take: limit }), this.prisma.temporaryReadingMaterial.count(), ]); - return { items, total, page, limit }; + const enriched = await this.enrichWithNames(items); return { items: enriched, total, page, limit }; } // ══ Operations ══