diff --git a/app/Http/Controllers/Admin/BasicSettings/MachinePhotoController.php b/app/Http/Controllers/Admin/BasicSettings/MachinePhotoController.php new file mode 100644 index 0000000..620ed77 --- /dev/null +++ b/app/Http/Controllers/Admin/BasicSettings/MachinePhotoController.php @@ -0,0 +1,113 @@ + $machine->id, + 'files' => $request->allFiles() + ]); + + try { + $images = $machine->images ?? []; + + // 處理 3 個索引位置的圖片 + for ($i = 0; $i < 3; $i++) { + // 先處理刪除標記 + if ($request->input("delete_photo_{$i}") === '1') { + if (isset($images[$i])) { + unset($images[$i]); + } + } + + // 再處理檔案上傳(若有上傳會覆蓋掉刪除邏輯或原有的圖) + $fieldName = "machine_image_{$i}"; + if ($request->hasFile($fieldName)) { + $file = $request->file($fieldName); + + // 轉為 WebP 格式與保存 + $path = $this->storeAsWebp($file, "machines/{$machine->id}"); + $images[$i] = $path; + + Log::info("Machine image uploaded at slot {$i}", ['path' => $path]); + } + } + + // 過濾掉 null 並重新整理索引,但這裡我們希望保持 3 個槽位的概念 + // 如果用戶想保持順序,我們就直接儲存 + ksort($images); + + $machine->update([ + 'images' => $images, + 'updater_id' => auth()->id(), + ]); + + return back()->with('success', __('Machine images updated successfully.')); + } catch (\Exception $e) { + Log::error('Machine Photo Update Failed', [ + 'machine_id' => $machine->id, + 'error' => $e->getMessage() + ]); + return back()->with('error', __('Failed to update machine images: ') . $e->getMessage()); + } + } + + /** + * 將圖片轉換為 WebP 並儲存 + */ + protected function storeAsWebp($file, $directory): string + { + $extension = $file->getClientOriginalExtension(); + $filename = uniqid() . '.webp'; + $path = "{$directory}/{$filename}"; + + // 讀取原始圖片 + $imageType = exif_imagetype($file->getRealPath()); + switch ($imageType) { + case IMAGETYPE_JPEG: + $source = imagecreatefromjpeg($file->getRealPath()); + break; + case IMAGETYPE_PNG: + $source = imagecreatefrompng($file->getRealPath()); + break; + case IMAGETYPE_WEBP: + $source = imagecreatefromwebp($file->getRealPath()); + break; + default: + // 如果格式不支援,直接存 + return $file->storeAs($directory, $file->hashName(), 'public'); + } + + if (!$source) { + return $file->storeAs($directory, $file->hashName(), 'public'); + } + + // 確保支援真彩色(解決 palette image 問題) + if (!imageistruecolor($source)) { + imagepalettetotruecolor($source); + } + + // 捕捉輸出 + ob_start(); + imagewebp($source, null, 80); + $content = ob_get_clean(); + imagedestroy($source); + + Storage::disk('public')->put($path, $content); + + return $path; + } +} diff --git a/database/seeders/AdminUserSeeder.php b/database/seeders/AdminUserSeeder.php index 27c1dda..8b4cfae 100644 --- a/database/seeders/AdminUserSeeder.php +++ b/database/seeders/AdminUserSeeder.php @@ -20,13 +20,13 @@ class AdminUserSeeder extends Seeder { // 檢查是否已存在 admin 帳號,避免重複建立 $admin = User::where('username', 'admin')->first(); - + if ($admin) { $this->command->info('Admin 帳號已存在,執行更新密碼與資料。'); $admin->update([ 'name' => 'Admin', 'email' => 'admin@star-cloud.com', - 'password' => Hash::make('password'), + 'password' => Hash::make('Star82779061'), ]); $admin->assignRole('super-admin'); return; @@ -43,4 +43,4 @@ class AdminUserSeeder extends Seeder $this->command->info('Admin 帳號建立成功!'); } -} +} \ No newline at end of file diff --git a/database/seeders/RoleSeeder.php b/database/seeders/RoleSeeder.php index b9d7fc3..2c21f3d 100644 --- a/database/seeders/RoleSeeder.php +++ b/database/seeders/RoleSeeder.php @@ -41,14 +41,14 @@ class RoleSeeder extends Seeder // 建立角色 $superAdmin = Role::updateOrCreate( - ['name' => 'super-admin'], - ['is_system' => true] + ['name' => 'super-admin'], + ['is_system' => true] ); $superAdmin->syncPermissions(Permission::all()); $tenantAdmin = Role::updateOrCreate( - ['name' => 'tenant-admin'], - ['is_system' => false] + ['name' => 'tenant-admin'], + ['is_system' => false] ); $tenantAdmin->syncPermissions([ 'menu.members', @@ -65,4 +65,4 @@ class RoleSeeder extends Seeder 'menu.special-permission', ]); } -} +} \ No newline at end of file diff --git a/lang/en.json b/lang/en.json index a3e7259..e75ffbf 100644 --- a/lang/en.json +++ b/lang/en.json @@ -373,5 +373,8 @@ "PS_MERCHANT_ID": "PS_MERCHANT_ID", "Save Config": "Save Config", "StoreID": "StoreID", - "TermID": "TermID" + "TermID": "TermID", + "Photo Slot": "Photo Slot", + "Optimized for display. Supported formats: JPG, PNG, WebP.": "Optimized for display. Supported formats: JPG, PNG, WebP.", + "Change": "Change" } \ No newline at end of file diff --git a/lang/ja.json b/lang/ja.json index 7d40c8c..daa5697 100644 --- a/lang/ja.json +++ b/lang/ja.json @@ -347,7 +347,7 @@ "Are you sure?": "よろしいですか?", "Serial No": "機台シリアル番号", "Select Owner": "所属会社を選択", - "Select Model": "Select Model", + "Select Model": "型番を選択", "Machines": "機台リスト", "Models": "型番リスト", "Edit": "編集", @@ -380,5 +380,8 @@ "PS_MERCHANT_ID": "全盈+Pay 加盟店ID", "EASY_MERCHANT_ID": "悠遊付 加盟店ID", "Save Config": "設定を保存", - "e.g., Company Standard Pay": "例:標準決済組合せ" + "e.g., Company Standard Pay": "例:標準決済組合せ", + "Photo Slot": "写真スロット", + "Optimized for display. Supported formats: JPG, PNG, WebP.": "表示用に最適化されています。対応形式:JPG, PNG, WebP。", + "Change": "変更" } \ No newline at end of file diff --git a/lang/zh_TW.json b/lang/zh_TW.json index b9cf95a..6e56b9c 100644 --- a/lang/zh_TW.json +++ b/lang/zh_TW.json @@ -411,5 +411,8 @@ "Delete": "刪除", "None": "無", "Select Company": "選擇所屬公司", - "e.g., Company Standard Pay": "例如:公司標準支付" + "e.g., Company Standard Pay": "例如:公司標準支付", + "Photo Slot": "照片欄位", + "Optimized for display. Supported formats: JPG, PNG, WebP.": "已針對顯示進行優化。支援格式:JPG, PNG, WebP。", + "Change": "更換" } \ No newline at end of file diff --git a/resources/views/admin/basic-settings/machines/edit.blade.php b/resources/views/admin/basic-settings/machines/edit.blade.php index f407e4e..8c77cc4 100644 --- a/resources/views/admin/basic-settings/machines/edit.blade.php +++ b/resources/views/admin/basic-settings/machines/edit.blade.php @@ -1,14 +1,7 @@ @extends('layouts.admin') @section('content') -
- * {{ __('You can upload images one by one. Supporting up to 3 slots.') }}
- * {{ __('Click any slot to select or replace a photo.') }}
-