1. 修正 ApkVersionController::store() 中 is_forced 欄位的判斷邏輯
2. 原邏輯使用 $request->has('is_forced') 判斷,但因表單含 hidden input (value=0),導致 key 永遠存在,has() 永遠回傳 true
3. 改用 $request->boolean('is_forced') 直接讀取欄位值,正確將字串 '0' 轉為 false、'1' 轉為 true
119 lines
4.2 KiB
PHP
119 lines
4.2 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers\Admin\BasicSettings;
|
||
|
||
use App\Http\Controllers\Admin\AdminController;
|
||
use App\Models\Machine\ApkVersion;
|
||
use App\Models\Machine\Machine;
|
||
use App\Services\Machine\MqttService;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Facades\Storage;
|
||
|
||
use Illuminate\View\View;
|
||
|
||
class ApkVersionController extends AdminController
|
||
{
|
||
public function index(): View
|
||
{
|
||
$versions = ApkVersion::orderBy('version_code', 'desc')->paginate(10);
|
||
// 用於 OTA 下發時讓使用者選擇的機台列表
|
||
$machines = Machine::all();
|
||
return view('admin.basic-settings.apk-versions.index', compact('versions', 'machines'));
|
||
}
|
||
|
||
public function create(): View
|
||
{
|
||
return view('admin.basic-settings.apk-versions.create');
|
||
}
|
||
|
||
public function store(Request $request)
|
||
{
|
||
$request->validate([
|
||
'version_name' => 'required|string|max:100',
|
||
'version_code' => 'required|integer|unique:apk_versions,version_code',
|
||
'flavor' => 'required|string|max:100',
|
||
'apk_file' => 'required_without:download_url|nullable|file|max:102400', // 上傳限制 100MB
|
||
'download_url' => 'required_without:apk_file|nullable|url|max:500',
|
||
'release_notes' => 'nullable|string',
|
||
'is_forced' => 'nullable|boolean',
|
||
]);
|
||
|
||
$filePath = null;
|
||
if ($request->hasFile('apk_file')) {
|
||
$filePath = $request->file('apk_file')->store('apks', 'public');
|
||
}
|
||
|
||
ApkVersion::create([
|
||
'version_name' => $request->version_name,
|
||
'version_code' => $request->version_code,
|
||
'flavor' => $request->flavor,
|
||
'file_path' => $filePath,
|
||
'download_url' => $request->download_url,
|
||
'release_notes' => $request->release_notes,
|
||
'is_forced' => $request->boolean('is_forced'),
|
||
]);
|
||
|
||
return redirect()->route('admin.basic-settings.apk-versions.index')
|
||
->with('success', __('APK version uploaded successfully.'));
|
||
}
|
||
|
||
public function destroy(ApkVersion $apkVersion)
|
||
{
|
||
if ($apkVersion->file_path) {
|
||
Storage::disk('public')->delete($apkVersion->file_path);
|
||
}
|
||
$apkVersion->delete();
|
||
|
||
return redirect()->route('admin.basic-settings.apk-versions.index')
|
||
->with('success', __('APK version deleted successfully.'));
|
||
}
|
||
|
||
/**
|
||
* 推送 OTA 更新指令給指定機台
|
||
*/
|
||
public function push(Request $request, ApkVersion $apkVersion, MqttService $mqttService)
|
||
{
|
||
$request->validate([
|
||
'machine_ids' => 'required|array',
|
||
'machine_ids.*' => 'exists:machines,id',
|
||
]);
|
||
|
||
$machines = Machine::whereIn('id', $request->machine_ids)->get();
|
||
$successCount = 0;
|
||
|
||
foreach ($machines as $machine) {
|
||
// 1. 先建立 RemoteCommand 紀錄,以取得自增 ID 作為 command_id(與系統慣例一致)
|
||
$command = \App\Models\Machine\RemoteCommand::create([
|
||
'machine_id' => $machine->id,
|
||
'user_id' => auth()->id(),
|
||
'command_type' => 'update_app',
|
||
'status' => 'pending',
|
||
'payload' => [
|
||
'url' => $apkVersion->url,
|
||
'version' => $apkVersion->version_name,
|
||
'version_code' => $apkVersion->version_code,
|
||
'is_forced' => $apkVersion->is_forced,
|
||
],
|
||
]);
|
||
|
||
// 2. 推播 MQTT,command_id 使用資料庫自增流水號
|
||
$pushed = $mqttService->pushCommand(
|
||
$machine->serial_no,
|
||
'update_app',
|
||
$command->payload,
|
||
(string) $command->id
|
||
);
|
||
|
||
if ($pushed) {
|
||
$successCount++;
|
||
} else {
|
||
// 推播失敗,將紀錄標記為失敗
|
||
$command->update(['status' => 'failed']);
|
||
}
|
||
}
|
||
|
||
return redirect()->route('admin.basic-settings.apk-versions.index')
|
||
->with('success', sprintf(__('OTA command sent to %d devices successfully.'), $successCount));
|
||
}
|
||
}
|