4baa4cb52b
後端:
- 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>
123 lines
3.4 KiB
Bash
123 lines
3.4 KiB
Bash
#!/bin/bash
|
||
set -e
|
||
|
||
echo "=== CFDivePlatform 容器初始化開始 ==="
|
||
|
||
# 檢查目錄結構
|
||
if [ ! -d "/var/www/storage" ]; then
|
||
echo "創建 storage 目錄..."
|
||
mkdir -p /var/www/storage
|
||
fi
|
||
|
||
if [ ! -d "/var/www/bootstrap/cache" ]; then
|
||
echo "創建 bootstrap/cache 目錄..."
|
||
mkdir -p /var/www/bootstrap/cache
|
||
fi
|
||
|
||
# 設置權限
|
||
echo "設置目錄權限..."
|
||
chown -R www-data:www-data /var/www
|
||
chmod -R 775 /var/www/storage /var/www/bootstrap/cache
|
||
|
||
# 等待 MySQL 服務啟動
|
||
echo "等待 MySQL 服務啟動..."
|
||
|
||
# 使用更穩定的方法檢查 MySQL 連接
|
||
MAX_TRIES=60
|
||
COUNT=0
|
||
|
||
wait_for_mysql() {
|
||
while [ $COUNT -lt $MAX_TRIES ]; do
|
||
if mysqladmin ping -h"db" -u"cfdiveuser" -p"cfdivepass" --silent 2>/dev/null; then
|
||
echo "✅ MySQL 服務已準備就緒"
|
||
return 0
|
||
fi
|
||
|
||
# 備用檢查方法
|
||
if php -r "
|
||
try {
|
||
\$pdo = new PDO('mysql:host=db;port=3306', 'cfdiveuser', 'cfdivepass');
|
||
echo 'PHP-PDO-OK';
|
||
exit(0);
|
||
} catch(Exception \$e) {
|
||
exit(1);
|
||
}
|
||
" 2>/dev/null; then
|
||
echo "✅ MySQL 連接成功 (通過 PHP PDO)"
|
||
break
|
||
fi
|
||
|
||
echo "⏳ 等待 MySQL... ($((COUNT+1))/$MAX_TRIES)"
|
||
sleep 2
|
||
COUNT=$((COUNT+1))
|
||
done
|
||
|
||
if [ $COUNT -eq $MAX_TRIES ]; then
|
||
echo "⚠️ 無法連接到 MySQL,但將繼續啟動服務"
|
||
fi
|
||
}
|
||
|
||
wait_for_mysql
|
||
|
||
# 檢查並安裝 Composer 依賴
|
||
echo "📦 檢查 Composer 依賴..."
|
||
if [ -f "composer.json" ]; then
|
||
if [ ! -d "vendor" ] || [ "composer.json" -nt "vendor/autoload.php" ]; then
|
||
echo "安裝 Composer 依賴..."
|
||
composer install --no-scripts --no-autoloader --optimize-autoloader
|
||
composer dump-autoload --optimize
|
||
else
|
||
echo "✅ Composer 依賴已是最新"
|
||
fi
|
||
fi
|
||
|
||
# 設置 Laravel 環境
|
||
if [ ! -f .env ]; then
|
||
echo "🔧 創建 .env 檔案..."
|
||
cp .env.example .env
|
||
php artisan key:generate
|
||
else
|
||
echo "✅ .env 檔案已存在"
|
||
fi
|
||
|
||
# 更新環境變數以確保正確配置
|
||
echo "🔧 更新資料庫配置..."
|
||
sed -i "s/DB_HOST=.*/DB_HOST=db/g" .env
|
||
sed -i "s/DB_PASSWORD=.*/DB_PASSWORD=cfdivepass/g" .env
|
||
sed -i "s/DB_USERNAME=.*/DB_USERNAME=cfdiveuser/g" .env
|
||
sed -i "s/DB_DATABASE=.*/DB_DATABASE=CFDivePlatform/g" .env
|
||
|
||
# 執行遷移(如果數據庫已準備好)
|
||
echo "🗄️ 執行數據庫遷移..."
|
||
if php artisan migrate:status 2>/dev/null; then
|
||
php artisan migrate --force || echo "⚠️ 遷移執行遇到問題,但繼續執行"
|
||
else
|
||
echo "⚠️ 無法檢查遷移狀態,跳過遷移"
|
||
fi
|
||
|
||
# 清除與優化 Laravel 緩存
|
||
echo "🧹 清除 Laravel 緩存..."
|
||
php artisan config:clear || true
|
||
php artisan cache:clear || true
|
||
php artisan route:clear || true
|
||
php artisan view:clear || true
|
||
|
||
# 生成 Swagger 文檔(如果可能)
|
||
if php -r "echo class_exists('L5Swagger\\L5SwaggerServiceProvider') ? 'yes' : 'no';" 2>/dev/null | grep -q 'yes'; then
|
||
echo "📖 生成 API 文檔..."
|
||
php artisan l5-swagger:generate || echo "⚠️ API 文檔生成失敗"
|
||
fi
|
||
|
||
echo "✅ CFDivePlatform 初始化完成!"
|
||
|
||
# 建立 storage symlink
|
||
echo "🔗 建立 storage symlink..."
|
||
php artisan storage:link --force || true
|
||
|
||
# 啟動 cron daemon(Laravel Scheduler)
|
||
echo "⏰ 啟動 Laravel Scheduler cron..."
|
||
service cron start || cron || true
|
||
|
||
# 執行傳入的命令
|
||
exec "$@"
|