fix: 修復圖片 URL 生成邏輯,確保返回完整的 Google Cloud Storage URLs
- 注入 IImageStorageService 到 FlashcardsController - 添加 GetImageUrlAsync 方法統一處理圖片 URL 生成 - 重構 GetFlashcards 從 LINQ 改為 foreach 迴圈支援異步操作 - 修復 GetFlashcard 方法的圖片 URL 處理邏輯 - 確保前端接收到完整的 GCS URLs 而非相對路徑 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
1a20a562d2
commit
a953509ba8
|
|
@ -6,6 +6,7 @@ using DramaLing.Api.Contracts.Services.Review;
|
|||
using Microsoft.AspNetCore.Authorization;
|
||||
using DramaLing.Api.Utils;
|
||||
using DramaLing.Api.Services;
|
||||
using DramaLing.Api.Services.Storage;
|
||||
using DramaLing.Api.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
|
|
@ -18,17 +19,33 @@ public class FlashcardsController : BaseController
|
|||
private readonly IFlashcardRepository _flashcardRepository;
|
||||
private readonly IReviewService _reviewService;
|
||||
private readonly DramaLingDbContext _context;
|
||||
private readonly IImageStorageService _imageStorageService;
|
||||
|
||||
public FlashcardsController(
|
||||
IFlashcardRepository flashcardRepository,
|
||||
IReviewService reviewService,
|
||||
DramaLingDbContext context,
|
||||
IImageStorageService imageStorageService,
|
||||
IAuthService authService,
|
||||
ILogger<FlashcardsController> logger) : base(logger, authService)
|
||||
{
|
||||
_flashcardRepository = flashcardRepository;
|
||||
_reviewService = reviewService;
|
||||
_context = context;
|
||||
_imageStorageService = imageStorageService;
|
||||
}
|
||||
|
||||
private async Task<string?> GetImageUrlAsync(string? relativePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(relativePath))
|
||||
return null;
|
||||
|
||||
// 確保路徑包含 examples/ 前綴
|
||||
var fullPath = relativePath.StartsWith("examples/")
|
||||
? relativePath
|
||||
: $"examples/{relativePath}";
|
||||
|
||||
return await _imageStorageService.GetImageUrlAsync(fullPath);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
|
|
@ -47,38 +64,50 @@ public class FlashcardsController : BaseController
|
|||
.Where(fr => fr.UserId == userId && flashcardIds.Contains(fr.FlashcardId))
|
||||
.ToDictionaryAsync(fr => fr.FlashcardId);
|
||||
|
||||
// 重構為 foreach 迴圈,支援異步 URL 處理
|
||||
var flashcardList = new List<object>();
|
||||
|
||||
foreach (var f in flashcards)
|
||||
{
|
||||
reviews.TryGetValue(f.Id, out var review);
|
||||
|
||||
// 取得主要圖片的相對路徑並轉換為完整 URL
|
||||
var primaryImageRelativePath = f.FlashcardExampleImages
|
||||
.Where(fei => fei.IsPrimary)
|
||||
.Select(fei => fei.ExampleImage.RelativePath)
|
||||
.FirstOrDefault();
|
||||
|
||||
var primaryImageUrl = await GetImageUrlAsync(primaryImageRelativePath);
|
||||
|
||||
flashcardList.Add(new
|
||||
{
|
||||
f.Id,
|
||||
f.Word,
|
||||
f.Translation,
|
||||
f.Definition,
|
||||
f.PartOfSpeech,
|
||||
f.Pronunciation,
|
||||
f.Example,
|
||||
f.ExampleTranslation,
|
||||
f.IsFavorite,
|
||||
f.Synonyms,
|
||||
DifficultyLevelNumeric = f.DifficultyLevelNumeric,
|
||||
CEFR = CEFRHelper.ToString(f.DifficultyLevelNumeric),
|
||||
f.CreatedAt,
|
||||
f.UpdatedAt,
|
||||
// 添加複習相關屬性
|
||||
NextReviewDate = review?.NextReviewDate ?? DateTime.UtcNow.AddDays(1),
|
||||
TimesReviewed = review?.TotalCorrectCount + review?.TotalWrongCount + review?.TotalSkipCount ?? 0,
|
||||
MasteryLevel = review?.SuccessCount ?? 0,
|
||||
// 添加圖片相關屬性
|
||||
HasExampleImage = f.FlashcardExampleImages.Any(),
|
||||
PrimaryImageUrl = primaryImageUrl
|
||||
});
|
||||
}
|
||||
|
||||
var flashcardData = new
|
||||
{
|
||||
Flashcards = flashcards.Select(f => {
|
||||
reviews.TryGetValue(f.Id, out var review);
|
||||
return new
|
||||
{
|
||||
f.Id,
|
||||
f.Word,
|
||||
f.Translation,
|
||||
f.Definition,
|
||||
f.PartOfSpeech,
|
||||
f.Pronunciation,
|
||||
f.Example,
|
||||
f.ExampleTranslation,
|
||||
f.IsFavorite,
|
||||
f.Synonyms,
|
||||
DifficultyLevelNumeric = f.DifficultyLevelNumeric,
|
||||
CEFR = CEFRHelper.ToString(f.DifficultyLevelNumeric),
|
||||
f.CreatedAt,
|
||||
f.UpdatedAt,
|
||||
// 添加複習相關屬性
|
||||
NextReviewDate = review?.NextReviewDate ?? DateTime.UtcNow.AddDays(1),
|
||||
TimesReviewed = review?.TotalCorrectCount + review?.TotalWrongCount + review?.TotalSkipCount ?? 0,
|
||||
MasteryLevel = review?.SuccessCount ?? 0,
|
||||
// 添加圖片相關屬性
|
||||
HasExampleImage = f.FlashcardExampleImages.Any(),
|
||||
PrimaryImageUrl = f.FlashcardExampleImages
|
||||
.Where(fei => fei.IsPrimary)
|
||||
.Select(fei => $"/images/examples/{fei.ExampleImage.RelativePath}")
|
||||
.FirstOrDefault()
|
||||
};
|
||||
}),
|
||||
Flashcards = flashcardList,
|
||||
Count = flashcards.Count()
|
||||
};
|
||||
|
||||
|
|
@ -181,10 +210,10 @@ public class FlashcardsController : BaseController
|
|||
MasteryLevel = review?.SuccessCount ?? 0,
|
||||
// 添加圖片相關屬性
|
||||
HasExampleImage = flashcard.FlashcardExampleImages.Any(),
|
||||
PrimaryImageUrl = flashcard.FlashcardExampleImages
|
||||
PrimaryImageUrl = await GetImageUrlAsync(flashcard.FlashcardExampleImages
|
||||
.Where(fei => fei.IsPrimary)
|
||||
.Select(fei => $"/images/examples/{fei.ExampleImage.RelativePath}")
|
||||
.FirstOrDefault(),
|
||||
.Select(fei => fei.ExampleImage.RelativePath)
|
||||
.FirstOrDefault()),
|
||||
// 保留完整的圖片關聯數據供前端使用
|
||||
FlashcardExampleImages = flashcard.FlashcardExampleImages
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue