Files
a620906209 4baa4cb52b feat:實作課程圖片上傳 — 封面 + 相簿管理
後端:
- Migration:diving_offers 新增 cover_image 欄位、新增 course_images 表(含索引)
- CourseImage Model(CREATED_AT、url accessor)
- DivingOffer:cover_image_url accessor、hasMany courseImages、static::deleting() 孤兒清理
- CourseImageController:封面上傳/刪除、相簿上傳(max 3)/刪除,統一 mimes+size 驗證
- DivingOfferController:index/show 回傳加入 cover_image_url 與 images 陣列
- 修正 APP_URL 加入 port(:8080),Storage::url() 才能產生正確圖片連結

前端:
- courseImageApi.js:uploadCover/deleteCover/uploadImage/deleteImage
- CourseCard:有封面顯示 <img>,無封面顯示漸層佔位
- CourseDetailView:封面大圖 + 相簿縮圖橫列(點擊開新分頁)
- OfferFormView(編輯模式):封面預覽/更換/刪除、相簿縮圖管理(達 3 張隱藏上傳按鈕)

基礎設施:
- docker-entrypoint.sh:加入 storage:link --force
- docker-compose.yml:移除 storage-data named volume(改用 bind mount,避免 Nginx 讀不到圖片)

測試:
- CourseImageTest.php:14 個 Feature Test 全部 PASS(Storage::fake)
  涵蓋:上傳成功/格式驗證/大小驗證/所有權、刪除/無封面不報錯、
        相簿上限/sort_order 遞增、孤兒清理

OpenSpec:
- course-images change 歸檔至 archive/2026-05-12-course-images
- 新增 specs/course-image-upload 主規格(含 bind mount 持久化說明)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-12 03:54:45 +08:00

2.0 KiB
Raw Permalink Blame History

Why

目前課程頁面以 🤿 emoji 作為佔位,缺乏視覺吸引力。課程圖片是潛水平台的核心體驗,直接影響會員瀏覽意願與教練品牌形象。

What Changes

  • 新增 diving_offers.cover_image 欄位:課程封面,顯示於課程卡與詳情頁頂部
  • 新增 course_images 資料表:相簿最多 3 張,顯示於課程詳情頁
  • 新增 Provider API:上傳/刪除封面、上傳/刪除相簿圖片
  • 更新前端:CourseCard 顯示封面、CourseDetailView 顯示封面 + 相簿、OfferFormView 加入圖片管理 UI
  • Docker volume 掛載 storage/app/public,圖片跨 build 持久化
  • php artisan storage:link 整合至 entrypoint,確保 symlink 正確

Capabilities

New Capabilities

  • course-image-upload:Provider 上傳課程封面與相簿圖片(本地 public disk、max 2MB、支援 jpg/jpeg/png/webp)、相簿上限 3 張、刪除圖片同步移除實體檔案

Modified Capabilities

  • coach-offers-api:新增圖片上傳/刪除端點,DivingOffer 回應加入 cover_image_urlimages

Impact

後端

  • Migrationdiving_offerscover_imagenullable string
  • Migration:新增 course_imagesid、diving_offer_id、image_path、sort_order
  • ModelCourseImageDivingOfferhasMany CourseImagecover_image_url accessor
  • ControllerCourseImageController(上傳封面、刪除封面、上傳相簿、刪除相簿)
  • Route/provider/offers/{id}/coverPOST/DELETE)、/provider/offers/{id}/imagesPOST)、/provider/images/{id}DELETE

前端

  • frontend/src/api/courseImageApi.js
  • CourseCard.vue:有封面顯示圖片,無封面顯示漸層佔位
  • CourseDetailView.vue:頂部大圖(封面)+ 相簿縮圖列
  • OfferFormView.vue(或新建 OfferImageManager.vue):封面上傳預覽、相簿管理

Docker

  • docker-compose.yml 新增 named volume storage-data 掛載 /var/www/storage/app/public
  • docker-entrypoint.sh 加入 php artisan storage:link --force