diff --git a/src/modules/knowledge-items/knowledge-items.repository.ts b/src/modules/knowledge-items/knowledge-items.repository.ts index f799783..fb78bb8 100644 --- a/src/modules/knowledge-items/knowledge-items.repository.ts +++ b/src/modules/knowledge-items/knowledge-items.repository.ts @@ -24,7 +24,7 @@ function detectSourceType(content?: string | null, title?: string): string | nul if (content.trimStart().startsWith('<')) return 'html'; // Markdown patterns - if (/^#{1,6}\s/.test(content) || /^[-*]\s/.test(content) || /\[.+\]\(.+\)/.test(content)) { + if (/^#{1,6}\s/.test(content) || /^[-*]\s/.test(content) || /\[.+?\]\(.+?\)/.test(content)) { return 'markdown'; } @@ -84,7 +84,8 @@ export class KnowledgeItemsRepository { } async findByKnowledgeBaseId(knowledgeBaseId: string, opts?: { sortBy?: string; order?: string }) { - const sortBy = opts?.sortBy ?? 'default'; + const validSortBy = ['createdAt', 'updatedAt', 'fileSize', 'default']; + const sortBy = (opts?.sortBy && validSortBy.includes(opts.sortBy)) ? opts.sortBy : 'default'; const order = opts?.order === 'asc' ? 'asc' : 'desc'; let orderBy: any; diff --git a/src/modules/knowledge-items/knowledge-items.service.ts b/src/modules/knowledge-items/knowledge-items.service.ts index 21cf44d..691e428 100644 --- a/src/modules/knowledge-items/knowledge-items.service.ts +++ b/src/modules/knowledge-items/knowledge-items.service.ts @@ -1,10 +1,12 @@ -import { Injectable, NotFoundException, ForbiddenException, BadRequestException } from '@nestjs/common'; +import { Injectable, NotFoundException, ForbiddenException, BadRequestException, Logger } from '@nestjs/common'; import { KnowledgeItemsRepository } from './knowledge-items.repository'; import { StorageService } from '../../infrastructure/storage/storage.service'; import { CosStorageProvider } from '../../infrastructure/storage/cos-storage.provider'; @Injectable() export class KnowledgeItemsService { + private readonly logger = new Logger(KnowledgeItemsService.name); + constructor( private readonly repository: KnowledgeItemsRepository, private readonly storage: StorageService, @@ -49,8 +51,8 @@ export class KnowledgeItemsService { enriched.fileSize = Number(headInfo.size); } return enriched; - } catch { - // If URL parsing fails, return original item unchanged + } catch (err) { + this.logger.warn(`enrichItem failed for item, returning original: ${(err as Error)?.message}`); } return item; } diff --git a/src/modules/learning-activity/learning-activity.service.ts b/src/modules/learning-activity/learning-activity.service.ts index f927180..b3c3729 100644 --- a/src/modules/learning-activity/learning-activity.service.ts +++ b/src/modules/learning-activity/learning-activity.service.ts @@ -89,7 +89,18 @@ export class LearningActivityService { } : undefined, }; - const aiResult = await this.trendWorkflow.execute(trendInput); + // AI analysis with 15s timeout fallback + let aiResult: any = {}; + try { + aiResult = await Promise.race([ + this.trendWorkflow.execute(trendInput), + new Promise((_, reject) => + setTimeout(() => reject(new Error('AI trend analysis timeout')), 15000) + ), + ]); + } catch (err) { + aiResult = { periodSummary: 'AI 分析暂不可用', overallScore: 0, overallDirection: 'stable', trends: [], strengths: [], weaknesses: [], recommendations: [], nextFocusAreas: [] }; + } return { ...aiResult, dailySeries }; } @@ -99,10 +110,12 @@ export class LearningActivityService { for (let i = days - 1; i >= 0; i--) { const d = new Date(now); d.setDate(d.getDate() - i); - const dateStr = d.toISOString().split('T')[0]; + // Use local date string to avoid UTC timezone shift issues + const dateStr = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; const dayActs = activities.filter((a) => { const ad = a.activityDate instanceof Date ? a.activityDate : new Date(a.activityDate); - return ad.toISOString().split('T')[0] === dateStr; + const adStr = `${ad.getFullYear()}-${String(ad.getMonth() + 1).padStart(2, '0')}-${String(ad.getDate()).padStart(2, '0')}`; + return adStr === dateStr; }); const minutes = Math.round(dayActs.reduce((s: number, a: any) => s + a.durationSeconds, 0) / 60); series.push({