diff --git a/backend/DramaLing.Api/Controllers/FlashcardsController.cs b/backend/DramaLing.Api/Controllers/FlashcardsController.cs index 8c97fed..b43375a 100644 --- a/backend/DramaLing.Api/Controllers/FlashcardsController.cs +++ b/backend/DramaLing.Api/Controllers/FlashcardsController.cs @@ -3,6 +3,7 @@ using Microsoft.EntityFrameworkCore; using DramaLing.Api.Data; using DramaLing.Api.Models.Entities; using DramaLing.Api.Models.DTOs; +using DramaLing.Api.Services.Storage; using Microsoft.AspNetCore.Authorization; using System.Security.Claims; @@ -15,11 +16,16 @@ public class FlashcardsController : ControllerBase { private readonly DramaLingDbContext _context; private readonly ILogger _logger; + private readonly IImageStorageService _imageStorageService; - public FlashcardsController(DramaLingDbContext context, ILogger logger) + public FlashcardsController( + DramaLingDbContext context, + ILogger logger, + IImageStorageService imageStorageService) { _context = context; _logger = logger; + _imageStorageService = imageStorageService; } private Guid GetUserId() @@ -50,6 +56,8 @@ public class FlashcardsController : ControllerBase var userId = GetUserId(); var query = _context.Flashcards + .Include(f => f.FlashcardExampleImages) + .ThenInclude(fei => fei.ExampleImage) .Where(f => f.UserId == userId && !f.IsArchived) .AsQueryable(); @@ -102,34 +110,61 @@ public class FlashcardsController : ControllerBase var flashcards = await query .AsNoTracking() // 效能優化:只讀查詢 .OrderByDescending(f => f.CreatedAt) - .Select(f => new - { - f.Id, - f.Word, - f.Translation, - f.Definition, - f.PartOfSpeech, - f.Pronunciation, - f.Example, - f.ExampleTranslation, - f.MasteryLevel, - f.TimesReviewed, - f.IsFavorite, - f.NextReviewDate, - f.DifficultyLevel, - f.CreatedAt, - f.UpdatedAt - // 移除 CardSet 屬性 - }) .ToListAsync(); + // 生成圖片資訊 + var flashcardDtos = new List(); + foreach (var flashcard in flashcards) + { + var exampleImages = new List(); + + // 處理關聯的圖片 + foreach (var flashcardImage in flashcard.FlashcardExampleImages) + { + var imageUrl = await _imageStorageService.GetImageUrlAsync(flashcardImage.ExampleImage.RelativePath); + + exampleImages.Add(new ExampleImageDto + { + Id = flashcardImage.ExampleImage.Id.ToString(), + ImageUrl = imageUrl, + IsPrimary = flashcardImage.IsPrimary, + QualityScore = flashcardImage.ExampleImage.QualityScore, + FileSize = flashcardImage.ExampleImage.FileSize, + CreatedAt = flashcardImage.ExampleImage.CreatedAt + }); + } + + flashcardDtos.Add(new + { + flashcard.Id, + flashcard.Word, + flashcard.Translation, + flashcard.Definition, + flashcard.PartOfSpeech, + flashcard.Pronunciation, + flashcard.Example, + flashcard.ExampleTranslation, + flashcard.MasteryLevel, + flashcard.TimesReviewed, + flashcard.IsFavorite, + flashcard.NextReviewDate, + flashcard.DifficultyLevel, + flashcard.CreatedAt, + flashcard.UpdatedAt, + // 新增圖片相關欄位 + ExampleImages = exampleImages, + HasExampleImage = exampleImages.Any(), + PrimaryImageUrl = exampleImages.FirstOrDefault(img => img.IsPrimary)?.ImageUrl + }); + } + return Ok(new { Success = true, Data = new { - Flashcards = flashcards, - Count = flashcards.Count + Flashcards = flashcardDtos, + Count = flashcardDtos.Count } }); } diff --git a/backend/DramaLing.Api/Data/DramaLingDbContext.cs b/backend/DramaLing.Api/Data/DramaLingDbContext.cs index 9a10718..02d000b 100644 --- a/backend/DramaLing.Api/Data/DramaLingDbContext.cs +++ b/backend/DramaLing.Api/Data/DramaLingDbContext.cs @@ -461,7 +461,7 @@ public class DramaLingDbContext : DbContext // 關聯關係 flashcardImageEntity .HasOne(fei => fei.Flashcard) - .WithMany() + .WithMany(f => f.FlashcardExampleImages) // 指定反向導航屬性 .HasForeignKey(fei => fei.FlashcardId) .OnDelete(DeleteBehavior.Cascade); diff --git a/backend/DramaLing.Api/Models/DTOs/FlashcardDto.cs b/backend/DramaLing.Api/Models/DTOs/FlashcardDto.cs index 16f9338..761ab5f 100644 --- a/backend/DramaLing.Api/Models/DTOs/FlashcardDto.cs +++ b/backend/DramaLing.Api/Models/DTOs/FlashcardDto.cs @@ -2,6 +2,16 @@ using System.ComponentModel.DataAnnotations; namespace DramaLing.Api.Models.DTOs; +public class ExampleImageDto +{ + public string Id { get; set; } = string.Empty; + public string ImageUrl { get; set; } = string.Empty; + public bool IsPrimary { get; set; } + public decimal? QualityScore { get; set; } + public int? FileSize { get; set; } + public DateTime CreatedAt { get; set; } +} + public class CreateFlashcardRequest { [Required(ErrorMessage = "詞彙為必填項目")] diff --git a/backend/DramaLing.Api/Models/Entities/Flashcard.cs b/backend/DramaLing.Api/Models/Entities/Flashcard.cs index e29994e..a7779d3 100644 --- a/backend/DramaLing.Api/Models/Entities/Flashcard.cs +++ b/backend/DramaLing.Api/Models/Entities/Flashcard.cs @@ -67,4 +67,5 @@ public class Flashcard public virtual ICollection StudyRecords { get; set; } = new List(); public virtual ICollection FlashcardTags { get; set; } = new List(); public virtual ICollection ErrorReports { get; set; } = new List(); + public virtual ICollection FlashcardExampleImages { get; set; } = new List(); } \ No newline at end of file