All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 59s
233 lines
8.8 KiB
PHP
233 lines
8.8 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Admin\BasicSettings;
|
|
|
|
use App\Http\Controllers\Admin\AdminController;
|
|
use App\Models\Machine\Machine;
|
|
use App\Models\Machine\MachineModel;
|
|
use App\Models\System\PaymentConfig;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\View\View;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Str;
|
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class MachineSettingController extends AdminController
|
|
{
|
|
/**
|
|
* 顯示機台與型號設定列表 (採用標籤頁整合)
|
|
*/
|
|
public function index(Request $request): View
|
|
{
|
|
$tab = $request->input('tab', 'machines');
|
|
$per_page = $request->input('per_page', 20);
|
|
$search = $request->input('search');
|
|
|
|
// 1. 處理機台清單 (Machines Tab)
|
|
$machineQuery = Machine::query()->with(['machineModel', 'paymentConfig', 'company']);
|
|
if ($tab === 'machines' && $search) {
|
|
$machineQuery->where(function ($q) use ($search) {
|
|
$q->where('name', 'like', "%{$search}%")
|
|
->orWhere('serial_no', 'like', "%{$search}%");
|
|
});
|
|
}
|
|
$machines = $machineQuery->latest()->paginate($per_page, ['*'], 'machines_page')->withQueryString();
|
|
|
|
// 2. 處理型號清單 (Models Tab)
|
|
$modelQuery = MachineModel::query()->withCount('machines');
|
|
if ($tab === 'models' && $search) {
|
|
$modelQuery->where('name', 'like', "%{$search}%");
|
|
}
|
|
$models_list = $modelQuery->latest()->paginate($per_page, ['*'], 'models_page')->withQueryString();
|
|
|
|
// 3. 基礎下拉資料 (用於新增/編輯機台的彈窗)
|
|
$models = MachineModel::select('id', 'name')->get();
|
|
$paymentConfigs = PaymentConfig::select('id', 'name')->get();
|
|
$companies = \App\Models\System\Company::select('id', 'name', 'code')->get();
|
|
|
|
return view('admin.basic-settings.machines.index', compact(
|
|
'machines',
|
|
'models_list',
|
|
'models',
|
|
'paymentConfigs',
|
|
'companies',
|
|
'tab'
|
|
));
|
|
}
|
|
|
|
/**
|
|
* 儲存新機台 (僅核心欄位)
|
|
*/
|
|
public function store(Request $request): RedirectResponse
|
|
{
|
|
$validated = $request->validate([
|
|
'name' => 'required|string|max:255',
|
|
'serial_no' => 'required|string|unique:machines,serial_no',
|
|
'company_id' => 'required|exists:companies,id',
|
|
'machine_model_id' => 'required|exists:machine_models,id',
|
|
'payment_config_id' => 'nullable|exists:payment_configs,id',
|
|
'location' => 'nullable|string|max:255',
|
|
'images.*' => 'image|mimes:jpeg,png,jpg,gif|max:2048',
|
|
]);
|
|
|
|
$imagePaths = [];
|
|
if ($request->hasFile('images')) {
|
|
foreach (array_slice($request->file('images'), 0, 3) as $image) {
|
|
$imagePaths[] = $this->processAndStoreImage($image);
|
|
}
|
|
}
|
|
|
|
$machine = Machine::create(array_merge($validated, [
|
|
'status' => 'offline',
|
|
'creator_id' => auth()->id(),
|
|
'updater_id' => auth()->id(),
|
|
'card_reader_seconds' => 30, // 預設值
|
|
'card_reader_checkout_time_1' => '22:30:00',
|
|
'card_reader_checkout_time_2' => '23:45:00',
|
|
'payment_buffer_seconds' => 5,
|
|
'images' => $imagePaths,
|
|
]));
|
|
|
|
return redirect()->route('admin.basic-settings.machines.index')
|
|
->with('success', __('Machine created successfully.'));
|
|
}
|
|
|
|
/**
|
|
* 顯示詳細編輯頁面
|
|
*/
|
|
public function edit(Machine $machine): View
|
|
{
|
|
$models = MachineModel::select('id', 'name')->get();
|
|
$paymentConfigs = PaymentConfig::select('id', 'name')->get();
|
|
$companies = \App\Models\System\Company::select('id', 'name', 'code')->get();
|
|
|
|
return view('admin.basic-settings.machines.edit', compact('machine', 'models', 'paymentConfigs', 'companies'));
|
|
}
|
|
|
|
/**
|
|
* 更新機台詳細參數
|
|
*/
|
|
public function update(Request $request, Machine $machine): RedirectResponse
|
|
{
|
|
Log::info('Machine Update Request', ['machine_id' => $machine->id, 'data' => $request->all()]);
|
|
|
|
try {
|
|
$validated = $request->validate([
|
|
'name' => 'required|string|max:255',
|
|
'card_reader_seconds' => 'required|integer|min:0',
|
|
'payment_buffer_seconds' => 'required|integer|min:0',
|
|
'card_reader_checkout_time_1' => 'nullable|string',
|
|
'card_reader_checkout_time_2' => 'nullable|string',
|
|
'heating_start_time' => 'nullable|string',
|
|
'heating_end_time' => 'nullable|string',
|
|
'card_reader_no' => 'nullable|string|max:255',
|
|
'key_no' => 'nullable|string|max:255',
|
|
'invoice_status' => 'required|integer|in:0,1,2',
|
|
'welcome_gift_enabled' => 'boolean',
|
|
'is_spring_slot_1_10' => 'boolean',
|
|
'is_spring_slot_11_20' => 'boolean',
|
|
'is_spring_slot_21_30' => 'boolean',
|
|
'is_spring_slot_31_40' => 'boolean',
|
|
'is_spring_slot_41_50' => 'boolean',
|
|
'is_spring_slot_51_60' => 'boolean',
|
|
'member_system_enabled' => 'boolean',
|
|
'machine_model_id' => 'required|exists:machine_models,id',
|
|
'payment_config_id' => 'nullable|exists:payment_configs,id',
|
|
'location' => 'nullable|string|max:255',
|
|
]);
|
|
|
|
// 僅限系統管理員可修改公司
|
|
if (auth()->user()->isSystemAdmin()) {
|
|
$companyRule = ['company_id' => 'nullable|exists:companies,id'];
|
|
$companyData = $request->validate($companyRule);
|
|
$validated = array_merge($validated, $companyData);
|
|
}
|
|
|
|
Log::info('Machine Update Validated Data', ['data' => $validated]);
|
|
} catch (\Illuminate\Validation\ValidationException $e) {
|
|
Log::error('Machine Update Validation Failed', ['errors' => $e->errors()]);
|
|
throw $e;
|
|
}
|
|
|
|
$machine->update(array_merge($validated, [
|
|
'updater_id' => auth()->id(),
|
|
]));
|
|
|
|
// 處理圖片更新 (支援 3 個獨立槽位)
|
|
if ($request->hasFile('images')) {
|
|
$currentImages = $machine->images ?? [];
|
|
$newImages = $request->file('images');
|
|
$updated = false;
|
|
|
|
foreach ($newImages as $index => $file) {
|
|
// 限制 3 個槽位 (0, 1, 2)
|
|
if ($index < 0 || $index > 2) continue;
|
|
|
|
// 刪除該槽位的舊圖
|
|
if (isset($currentImages[$index]) && !empty($currentImages[$index])) {
|
|
\Illuminate\Support\Facades\Storage::disk('public')->delete($currentImages[$index]);
|
|
}
|
|
|
|
// 處理並儲存新圖
|
|
$currentImages[$index] = $this->processAndStoreImage($file);
|
|
$updated = true;
|
|
}
|
|
|
|
if ($updated) {
|
|
ksort($currentImages);
|
|
$machine->update(['images' => array_values($currentImages)]);
|
|
}
|
|
}
|
|
|
|
return redirect()->route('admin.basic-settings.machines.index')
|
|
->with('success', __('Machine settings updated successfully.'));
|
|
}
|
|
|
|
/**
|
|
* 處理並儲存圖片 (轉換為 WebP 並調整大小)
|
|
*/
|
|
protected function processAndStoreImage($file)
|
|
{
|
|
$path = 'machines/' . \Illuminate\Support\Str::random(40) . '.webp';
|
|
|
|
// 載入原圖
|
|
$imageInfo = getimagesize($file->getRealPath());
|
|
$mime = $imageInfo['mime'];
|
|
|
|
switch ($mime) {
|
|
case 'image/jpeg':
|
|
$image = imagecreatefromjpeg($file->getRealPath());
|
|
break;
|
|
case 'image/png':
|
|
$image = imagecreatefrompng($file->getRealPath());
|
|
break;
|
|
case 'image/gif':
|
|
$image = imagecreatefromgif($file->getRealPath());
|
|
break;
|
|
default:
|
|
return $file->store('machines', 'public');
|
|
}
|
|
|
|
if ($image) {
|
|
// [修正] imagewebp(): Palette image not supported by webp
|
|
// 若為 Palette 圖片 (例如 GIF),轉換為 Truecolor
|
|
if (!imageistruecolor($image)) {
|
|
imagepalettetotruecolor($image);
|
|
}
|
|
|
|
\Illuminate\Support\Facades\Storage::disk('public')->makeDirectory('machines');
|
|
$fullPath = \Illuminate\Support\Facades\Storage::disk('public')->path($path);
|
|
|
|
// 轉換並儲存 (品質 80)
|
|
imagewebp($image, $fullPath, 80);
|
|
imagedestroy($image);
|
|
|
|
return $path;
|
|
}
|
|
|
|
return $file->store('machines', 'public');
|
|
}
|
|
}
|