From 2a2c47da48a6e876a378cb9a990c4add3da4144c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=84=AD=E6=B2=9B=E8=BB=92?= Date: Sun, 5 Oct 2025 05:14:25 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E6=AD=A3=E5=9C=96=E7=89=87?= =?UTF-8?q?=E8=BC=89=E5=85=A5=E5=A4=B1=E6=95=97=20+=20=E6=B8=85=E7=90=86?= =?UTF-8?q?=E6=9C=AA=E4=BD=BF=E7=94=A8=E7=9A=84=20CSS=20=E6=AA=94=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 修正圖片載入問題 - ✅ 移除 flashcardUtils.ts 中的硬編碼端口 - ✅ 使用統一的 API_CONFIG.BASE_URL 配置 - ✅ 圖片 URL 現在自動跟隨後端配置 - ✅ 添加圖片載入失敗的錯誤處理 ## 代碼清理 - 🗑️ 移除未使用的 review-simple/globals.css - 🗑️ 移除對應的 CSS import - ✅ 所有組件使用 Tailwind CSS,保持一致性 ## 技術改進 - 🔧 消除硬編碼,提升維護性 - ⚙️ 統一配置管理,環境變數驅動 - 🛡️ 更好的錯誤處理和用戶體驗 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- frontend/app/review-simple/globals.css | 107 ------------------ frontend/app/review-simple/page.tsx | 1 - .../flashcards/FlashcardContentBlocks.tsx | 19 ++++ frontend/lib/utils/flashcardUtils.ts | 8 +- 4 files changed, 24 insertions(+), 111 deletions(-) delete mode 100644 frontend/app/review-simple/globals.css diff --git a/frontend/app/review-simple/globals.css b/frontend/app/review-simple/globals.css deleted file mode 100644 index 376c3a3..0000000 --- a/frontend/app/review-simple/globals.css +++ /dev/null @@ -1,107 +0,0 @@ -/* 極簡MVP專用CSS - 復用現有的精美設計 */ - -/* 高級3D翻卡動畫 (來自原FlipMemoryTest設計) */ -.flip-card-container { - perspective: 1000px; -} - -.flip-card { - position: relative; - width: 100%; - height: 100%; - transform-style: preserve-3d; - transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1); - cursor: pointer; -} - -.flip-card.flipped { - transform: rotateY(180deg); -} - -.flip-card-front, -.flip-card-back { - position: absolute; - width: 100%; - height: 100%; - backface-visibility: hidden; - border-radius: 0.75rem; - box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); -} - -.flip-card-back { - transform: rotateY(180deg); -} - -.flip-card:hover .flip-card-front, -.flip-card:hover .flip-card-back { - box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); -} - -/* 信心度按鈕 (復用ConfidenceButtons設計) */ -.confidence-button { - transition: all 0.2s ease-in-out; - border: 2px solid; - border-radius: 0.5rem; - padding: 0.75rem; - font-weight: 500; -} - -.confidence-button:hover:not(:disabled) { - transform: scale(1.02); -} - -.confidence-button.selected { - transform: scale(1.05); - ring: 2px; - ring-color: rgba(59, 130, 246, 0.75); - ring-offset: 2px; -} - -.confidence-button:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -/* 進度條平滑動畫 */ -.progress-bar { - transition: width 0.3s ease-in-out; -} - -/* 響應式設計 (復用原有邏輯) */ -@media (max-width: 480px) { - .flip-card-container { - min-height: 300px; - } -} - -@media (min-width: 481px) and (max-width: 768px) { - .flip-card-container { - min-height: 350px; - } -} - -@media (min-width: 769px) { - .flip-card-container { - min-height: 400px; - } -} - -/* 內容區塊樣式 (復用原有設計) */ -.content-block { - background-color: #f9fafb; - border-radius: 0.5rem; - padding: 1rem; - margin-bottom: 0.75rem; -} - -.content-block h3 { - font-weight: 600; - color: #111827; - margin-bottom: 0.5rem; - text-align: left; -} - -.content-block p { - color: #374151; - text-align: left; -} \ No newline at end of file diff --git a/frontend/app/review-simple/page.tsx b/frontend/app/review-simple/page.tsx index 27eecc7..83c6cc5 100644 --- a/frontend/app/review-simple/page.tsx +++ b/frontend/app/review-simple/page.tsx @@ -1,7 +1,6 @@ 'use client' import { Navigation } from '@/components/shared/Navigation' -import './globals.css' import { FlipMemory } from '@/components/review/quiz/FlipMemory' import { VocabChoiceQuiz } from '@/components/review/quiz/VocabChoiceQuiz' import { QuizProgress } from '@/components/review/ui/QuizProgress' diff --git a/frontend/components/flashcards/FlashcardContentBlocks.tsx b/frontend/components/flashcards/FlashcardContentBlocks.tsx index ee57a5a..97cc2db 100644 --- a/frontend/components/flashcards/FlashcardContentBlocks.tsx +++ b/frontend/components/flashcards/FlashcardContentBlocks.tsx @@ -72,6 +72,25 @@ export const FlashcardContentBlocks: React.FC = ({ alt={`${flashcard.word} example`} className="w-full aspect-square object-cover rounded-lg border border-blue-300" style={{ imageRendering: 'auto' }} + onError={(e) => { + console.error('圖片載入失敗:', getFlashcardImageUrl(flashcard)) + // 隱藏破損的圖片,顯示無圖片狀態 + e.currentTarget.style.display = 'none' + const parent = e.currentTarget.parentElement?.parentElement + if (parent) { + parent.innerHTML = ` +
+
+ + + +

圖片載入失敗

+

請檢查後端服務是否正常運行

+
+
+ ` + } + }} /> ) : ( diff --git a/frontend/lib/utils/flashcardUtils.ts b/frontend/lib/utils/flashcardUtils.ts index 511d59b..e5d111c 100644 --- a/frontend/lib/utils/flashcardUtils.ts +++ b/frontend/lib/utils/flashcardUtils.ts @@ -3,6 +3,8 @@ * 統一管理詞卡相關的顯示和處理邏輯 */ +import { API_CONFIG } from '@/lib/config/api' + // 詞性簡寫轉換 export const getPartOfSpeechDisplay = (partOfSpeech: string): string => { const shortMap: {[key: string]: string} = { @@ -77,7 +79,7 @@ export const getFlashcardImageUrl = (flashcard: any): string | null => { if (flashcard.primaryImageUrl) { // 如果是相對路徑,加上後端基礎 URL if (flashcard.primaryImageUrl.startsWith('/')) { - return `http://localhost:5008${flashcard.primaryImageUrl}` + return `${API_CONFIG.BASE_URL}${flashcard.primaryImageUrl}` } return flashcard.primaryImageUrl } @@ -87,10 +89,10 @@ export const getFlashcardImageUrl = (flashcard: any): string | null => { const primaryImage = flashcard.exampleImages.find((img: any) => img.isPrimary) if (primaryImage) { const imageUrl = primaryImage.imageUrl - return imageUrl?.startsWith('/') ? `http://localhost:5008${imageUrl}` : imageUrl + return imageUrl?.startsWith('/') ? `${API_CONFIG.BASE_URL}${imageUrl}` : imageUrl } const firstImageUrl = flashcard.exampleImages[0].imageUrl - return firstImageUrl?.startsWith('/') ? `http://localhost:5008${firstImageUrl}` : firstImageUrl + return firstImageUrl?.startsWith('/') ? `${API_CONFIG.BASE_URL}${firstImageUrl}` : firstImageUrl } return null