diff --git a/.gitea/workflows/deploy-demo.yaml b/.gitea/workflows/deploy-demo.yaml index 79b4de5..8816231 100644 --- a/.gitea/workflows/deploy-demo.yaml +++ b/.gitea/workflows/deploy-demo.yaml @@ -96,6 +96,7 @@ jobs: php artisan optimize:clear && php artisan optimize && php artisan view:cache && + php artisan queue:restart && php artisan db:seed --class=RoleSeeder --force && php artisan db:seed --class=AdminUserSeeder --force " diff --git a/app/Http/Controllers/Admin/BasicSettings/MachineSettingController.php b/app/Http/Controllers/Admin/BasicSettings/MachineSettingController.php index a000c1c..d421ab5 100644 --- a/app/Http/Controllers/Admin/BasicSettings/MachineSettingController.php +++ b/app/Http/Controllers/Admin/BasicSettings/MachineSettingController.php @@ -84,6 +84,7 @@ class MachineSettingController extends AdminController $machine = Machine::create(array_merge($validated, [ 'status' => 'offline', + 'api_token' => \Illuminate\Support\Str::random(60), 'creator_id' => auth()->id(), 'updater_id' => auth()->id(), 'card_reader_seconds' => 30, // 預設值 @@ -119,6 +120,7 @@ class MachineSettingController extends AdminController try { $validated = $request->validate([ 'name' => 'required|string|max:255', + 'serial_no' => 'sometimes|required|string|unique:machines,serial_no,' . $machine->id, 'card_reader_seconds' => 'required|integer|min:0', 'payment_buffer_seconds' => 'required|integer|min:0', 'card_reader_checkout_time_1' => 'nullable|string', @@ -187,4 +189,25 @@ class MachineSettingController extends AdminController return redirect()->route('admin.basic-settings.machines.index') ->with('success', __('Machine settings updated successfully.')); } + + public function regenerateToken(Request $request, $serial): \Illuminate\Http\JsonResponse + { + // 僅使用機台序號 (serial_no) 作為識別碼,最直覺且穩定 + $machine = Machine::where('serial_no', $serial)->firstOrFail(); + + $newToken = \Illuminate\Support\Str::random(60); + $machine->update(['api_token' => $newToken]); + + \Log::info('Machine API Token Regenerated', [ + 'machine_id' => $machine->id, + 'serial_no' => $machine->serial_no, + 'user_id' => auth()->id() + ]); + + return response()->json([ + 'success' => true, + 'api_token' => $newToken, + 'message' => __('API Token regenerated successfully.') + ]); + } } diff --git a/app/Http/Controllers/Admin/QrCodeController.php b/app/Http/Controllers/Admin/QrCodeController.php new file mode 100644 index 0000000..1315c58 --- /dev/null +++ b/app/Http/Controllers/Admin/QrCodeController.php @@ -0,0 +1,34 @@ +query('data'); + $size = $request->query('size', 250); + + if (!$data) { + return response()->noContent(); + } + + // Generate SVG QR Code + $qrCode = QrCode::size($size) + ->format('svg') + ->margin(1) + ->generate($data); + + return response($qrCode)->header('Content-Type', 'image/svg+xml'); + } +} diff --git a/compose.yaml b/compose.yaml index 52ff10e..82e774f 100644 --- a/compose.yaml +++ b/compose.yaml @@ -28,6 +28,24 @@ services: - mysql - redis + laravel.queue: + image: 'sail-8.5/app' + container_name: star-cloud-queue + hostname: star-cloud-queue + command: php artisan queue:work --tries=3 --timeout=90 + environment: + WWWUSER: '${WWWUSER}' + LARAVEL_SAIL: 1 + TZ: 'Asia/Taipei' + volumes: + - '.:/var/www/html' + networks: + - sail + depends_on: + - mysql + - redis + restart: always + mysql: image: 'mysql/mysql-server:8.0' container_name: star-cloud-mysql diff --git a/composer.json b/composer.json index 0b68ad9..537e081 100644 --- a/composer.json +++ b/composer.json @@ -14,6 +14,7 @@ "laravel/framework": "^12.0", "laravel/sanctum": "^4.3", "laravel/tinker": "^2.10.1", + "simplesoftwareio/simple-qrcode": "^4.2", "spatie/laravel-permission": "^7.2" }, "require-dev": { diff --git a/composer.lock b/composer.lock index d3219e0..39b5199 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,62 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a723334f883b537b67e4475890eb949e", + "content-hash": "2889e194212440faeb9f8f3dd7513795", "packages": [ + { + "name": "bacon/bacon-qr-code", + "version": "2.0.8", + "source": { + "type": "git", + "url": "https://github.com/Bacon/BaconQrCode.git", + "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/8674e51bb65af933a5ffaf1c308a660387c35c22", + "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22", + "shasum": "" + }, + "require": { + "dasprid/enum": "^1.0.3", + "ext-iconv": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phly/keep-a-changelog": "^2.1", + "phpunit/phpunit": "^7 | ^8 | ^9", + "spatie/phpunit-snapshot-assertions": "^4.2.9", + "squizlabs/php_codesniffer": "^3.4" + }, + "suggest": { + "ext-imagick": "to generate QR code images" + }, + "type": "library", + "autoload": { + "psr-4": { + "BaconQrCode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "description": "BaconQrCode is a QR code generator for PHP.", + "homepage": "https://github.com/Bacon/BaconQrCode", + "support": { + "issues": "https://github.com/Bacon/BaconQrCode/issues", + "source": "https://github.com/Bacon/BaconQrCode/tree/2.0.8" + }, + "time": "2022-12-07T17:46:57+00:00" + }, { "name": "brick/math", "version": "0.14.8", @@ -135,6 +189,56 @@ ], "time": "2024-02-09T16:56:22+00:00" }, + { + "name": "dasprid/enum", + "version": "1.0.7", + "source": { + "type": "git", + "url": "https://github.com/DASPRiD/Enum.git", + "reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/b5874fa9ed0043116c72162ec7f4fb50e02e7cce", + "reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce", + "shasum": "" + }, + "require": { + "php": ">=7.1 <9.0" + }, + "require-dev": { + "phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11", + "squizlabs/php_codesniffer": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "DASPRiD\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "description": "PHP 7.1 enum implementation", + "keywords": [ + "enum", + "map" + ], + "support": { + "issues": "https://github.com/DASPRiD/Enum/issues", + "source": "https://github.com/DASPRiD/Enum/tree/1.0.7" + }, + "time": "2025-09-16T12:23:56+00:00" + }, { "name": "dflydev/dot-access-data", "version": "v3.0.3", @@ -3554,6 +3658,74 @@ }, "time": "2025-12-14T04:43:48+00:00" }, + { + "name": "simplesoftwareio/simple-qrcode", + "version": "4.2.0", + "source": { + "type": "git", + "url": "https://github.com/SimpleSoftwareIO/simple-qrcode.git", + "reference": "916db7948ca6772d54bb617259c768c9cdc8d537" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SimpleSoftwareIO/simple-qrcode/zipball/916db7948ca6772d54bb617259c768c9cdc8d537", + "reference": "916db7948ca6772d54bb617259c768c9cdc8d537", + "shasum": "" + }, + "require": { + "bacon/bacon-qr-code": "^2.0", + "ext-gd": "*", + "php": ">=7.2|^8.0" + }, + "require-dev": { + "mockery/mockery": "~1", + "phpunit/phpunit": "~9" + }, + "suggest": { + "ext-imagick": "Allows the generation of PNG QrCodes.", + "illuminate/support": "Allows for use within Laravel." + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "QrCode": "SimpleSoftwareIO\\QrCode\\Facades\\QrCode" + }, + "providers": [ + "SimpleSoftwareIO\\QrCode\\QrCodeServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "SimpleSoftwareIO\\QrCode\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Simple Software LLC", + "email": "support@simplesoftware.io" + } + ], + "description": "Simple QrCode is a QR code generator made for Laravel.", + "homepage": "https://www.simplesoftware.io/#/docs/simple-qrcode", + "keywords": [ + "Simple", + "generator", + "laravel", + "qrcode", + "wrapper" + ], + "support": { + "issues": "https://github.com/SimpleSoftwareIO/simple-qrcode/issues", + "source": "https://github.com/SimpleSoftwareIO/simple-qrcode/tree/4.2.0" + }, + "time": "2021-02-08T20:43:55+00:00" + }, { "name": "spatie/laravel-package-tools", "version": "1.93.0", diff --git a/lang/en.json b/lang/en.json index 3fc6e15..98e1de2 100644 --- a/lang/en.json +++ b/lang/en.json @@ -702,5 +702,11 @@ "Confirm Account Deactivation": "Confirm Deactivation", "Are you sure you want to deactivate this account? After deactivating, this account will no longer be able to log in to the system.": "Are you sure you want to deactivate this account? After deactivating, this account will no longer be able to log in to the system.", "Enable": "Enable", - "Disable": "Disable" -} + "Disable": "Disable", + "Regenerate": "Regenerate", + "API Token Copied": "API Token Copied", + "Yes, regenerate": "Yes, regenerate", + "Regenerating the token will disconnect the physical machine until it is updated. Continue?": "Regenerating the token will disconnect the physical machine until it is updated. Continue?", + "Error processing request": "Error processing request", + "API Token regenerated successfully.": "API Token regenerated successfully." +} \ No newline at end of file diff --git a/lang/ja.json b/lang/ja.json index 87c0b6a..116a409 100644 --- a/lang/ja.json +++ b/lang/ja.json @@ -703,5 +703,11 @@ "Confirm Account Deactivation": "アカウント停止の確認", "Are you sure you want to deactivate this account? After deactivating, this account will no longer be able to log in to the system.": "アカウントを停止してもよろしいですか?一旦停止するとシステムにログインできなくなります。", "Enable": "有効にする", - "Disable": "無効にする" -} + "Disable": "無効にする", + "Regenerate": "再生成する", + "API Token Copied": "APIトークンがコピーされました", + "Yes, regenerate": "はい、再生成します", + "Regenerating the token will disconnect the physical machine until it is updated. Continue?": "トークンを再生成すると、更新されるまで物理マシンの接続が切断されます。続行しますか?", + "Error processing request": "リクエストの処理中にエラーが発生しました", + "API Token regenerated successfully.": "APIトークンが正常に再生成されました。" +} \ No newline at end of file diff --git a/lang/zh_TW.json b/lang/zh_TW.json index 4248694..30fd97a 100644 --- a/lang/zh_TW.json +++ b/lang/zh_TW.json @@ -699,5 +699,11 @@ "Confirm Account Deactivation": "停用帳號確認", "Are you sure you want to deactivate this account? After deactivating, this account will no longer be able to log in to the system.": "確定要停用此帳號嗎?停用後將無法登入系統。", "Enable": "啟用", - "Disable": "停用" -} + "Disable": "停用", + "Regenerate": "重新產生", + "API Token Copied": "API 金鑰已複製", + "Yes, regenerate": "確認重新產生", + "Regenerating the token will disconnect the physical machine until it is updated. Continue?": "重新產生金鑰將導致實體機台暫時失去連線,必須於機台端更新此新金鑰才能恢復。確定繼續嗎?", + "Error processing request": "處理請求時發生錯誤", + "API Token regenerated successfully.": "API 金鑰重新產生成功。" +} \ No newline at end of file diff --git a/public/S1.png b/public/S1.png new file mode 100644 index 0000000..93a4ba8 Binary files /dev/null and b/public/S1.png differ diff --git a/public/S1_edited.png b/public/S1_edited.png new file mode 100644 index 0000000..e76ddd1 Binary files /dev/null and b/public/S1_edited.png differ diff --git a/resources/views/admin/basic-settings/machines/edit.blade.php b/resources/views/admin/basic-settings/machines/edit.blade.php index 341d10a..22d7cf4 100644 --- a/resources/views/admin/basic-settings/machines/edit.blade.php +++ b/resources/views/admin/basic-settings/machines/edit.blade.php @@ -74,7 +74,7 @@
- +
diff --git a/resources/views/admin/basic-settings/machines/index.blade.php b/resources/views/admin/basic-settings/machines/index.blade.php index fe809ec..c32d5f3 100644 --- a/resources/views/admin/basic-settings/machines/index.blade.php +++ b/resources/views/admin/basic-settings/machines/index.blade.php @@ -2,6 +2,7 @@ @section('content')
+}" @execute-regenerate.window="executeRegeneration($event.detail)">
@@ -149,7 +201,7 @@ @forelse($machines as $machine) - +
@@ -175,7 +227,7 @@
- + {{ $machine->machineModel->name ?? '--' }} @@ -183,7 +235,7 @@ @php - $isOnline = $machine->last_heartbeat_at && $machine->last_heartbeat_at->diffInMinutes() < 5; + $isOnline = $machine->last_heartbeat_at && $machine->last_heartbeat_at->diffInSeconds() < 30; @endphp
@if($isOnline) @@ -396,22 +448,25 @@
+ class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2"> + {{ __('Machine Name') }} * +
+ class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2"> + {{ __('Serial No') }} * +
+ class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2"> + {{ __('Owner') }} + @foreach($companies as $company)
+ class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2"> + {{ __('Location') }} +
+ class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2"> + {{ __('Model') }} + @foreach($models as $model) @@ -439,8 +496,9 @@
+ class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2"> + {{ __('Machine Images') }} ({{ __('Max 3') }}) +