[FEAT] 機台權限功能增強、UI 輕巧化與多語系優化
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 46s

This commit is contained in:
2026-03-30 16:15:04 +08:00
parent f3b2c3e018
commit 2c9dc793d7
10 changed files with 248 additions and 142 deletions

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers\Admin\Machine; namespace App\Http\Controllers\Admin\Machine;
use App\Http\Controllers\Admin\AdminController; use App\Http\Controllers\Admin\AdminController;
use App\Models\System\Company;
use App\Models\Machine\Machine; use App\Models\Machine\Machine;
use App\Models\System\User; use App\Models\System\User;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@@ -19,6 +20,7 @@ class MachinePermissionController extends AdminController
{ {
$per_page = $request->input('per_page', 10); $per_page = $request->input('per_page', 10);
$search = $request->input('search'); $search = $request->input('search');
$company_id = $request->input('company_id');
$currentUser = auth()->user(); $currentUser = auth()->user();
@@ -33,6 +35,9 @@ class MachinePermissionController extends AdminController
// 非系統管理員僅能看到同公司的帳號 (因 User Model 排除 TenantScoped 全域過濾,需手動注入) // 非系統管理員僅能看到同公司的帳號 (因 User Model 排除 TenantScoped 全域過濾,需手動注入)
if (!$currentUser->isSystemAdmin()) { if (!$currentUser->isSystemAdmin()) {
$userQuery->where('company_id', $currentUser->company_id); $userQuery->where('company_id', $currentUser->company_id);
} elseif ($company_id) {
// 系統管理員的篩選邏輯
$userQuery->where('company_id', $company_id);
} }
if ($search) { if ($search) {
@@ -44,8 +49,9 @@ class MachinePermissionController extends AdminController
} }
$users_list = $userQuery->latest()->paginate($per_page)->withQueryString(); $users_list = $userQuery->latest()->paginate($per_page)->withQueryString();
$companies = $currentUser->isSystemAdmin() ? Company::all() : collect();
return view('admin.machines.permissions', compact('users_list')); return view('admin.machines.permissions', compact('users_list', 'companies'));
} }
/** /**

View File

@@ -22,6 +22,7 @@ class MaintenanceController extends Controller
$this->authorize('viewAny', MaintenanceRecord::class); $this->authorize('viewAny', MaintenanceRecord::class);
$query = MaintenanceRecord::with(['machine', 'user', 'company']) $query = MaintenanceRecord::with(['machine', 'user', 'company'])
->whereHas('machine') // 確保僅顯示該帳號「看得見」的機台紀錄,避開因權限隔離導致的 null 報錯
->latest('maintenance_at'); ->latest('maintenance_at');
// 搜尋邏輯 // 搜尋邏輯

View File

@@ -73,10 +73,14 @@
"Assign Machines": "Assign Machines", "Assign Machines": "Assign Machines",
"Assigned Machines": "Assigned Machines", "Assigned Machines": "Assigned Machines",
"Audit Management": "Audit Management", "Audit Management": "Audit Management",
"Authorization updated successfully": "Authorization updated successfully",
"Authorize": "Authorize", "Authorize": "Authorize",
"Authorize Btn": "Authorize",
"Authorized Accounts": "Authorized Accounts", "Authorized Accounts": "Authorized Accounts",
"Authorized Accounts Tab": "Authorized Accounts",
"Authorized Machines": "Authorized Machines", "Authorized Machines": "Authorized Machines",
"Authorized Machines Management": "Authorized Machines Management", "Authorized Machines Management": "Authorized Machines Management",
"Authorized Status": "Authorized",
"Availability": "可用性 (Availability)", "Availability": "可用性 (Availability)",
"Available Machines": "可供分配的機台", "Available Machines": "可供分配的機台",
"Avatar updated successfully.": "Avatar updated successfully.", "Avatar updated successfully.": "Avatar updated successfully.",
@@ -183,7 +187,6 @@
"Delete Product Confirmation": "Delete Product Confirmation", "Delete Product Confirmation": "Delete Product Confirmation",
"Deposit Bonus": "Deposit Bonus", "Deposit Bonus": "Deposit Bonus",
"Describe the repair or maintenance status...": "Describe the repair or maintenance status...", "Describe the repair or maintenance status...": "Describe the repair or maintenance status...",
"Deselect All": "取消全選",
"Detail": "Detail", "Detail": "Detail",
"Device Information": "Device Information", "Device Information": "Device Information",
"Device Status Logs": "Device Status Logs", "Device Status Logs": "Device Status Logs",
@@ -324,7 +327,6 @@
"Machine Model Settings": "Machine Model Settings", "Machine Model Settings": "Machine Model Settings",
"Machine Name": "Machine Name", "Machine Name": "Machine Name",
"Machine Permissions": "Machine Permissions", "Machine Permissions": "Machine Permissions",
"Manage machine access permissions": "Manage machine access permissions",
"Machine Registry": "Machine Registry", "Machine Registry": "Machine Registry",
"Machine Reports": "Machine Reports", "Machine Reports": "Machine Reports",
"Machine Restart": "Machine Restart", "Machine Restart": "Machine Restart",
@@ -354,6 +356,7 @@
"Manage Expiry": "Manage Expiry", "Manage Expiry": "Manage Expiry",
"Manage administrative and tenant accounts": "Manage administrative and tenant accounts", "Manage administrative and tenant accounts": "Manage administrative and tenant accounts",
"Manage all tenant accounts and validity": "Manage all tenant accounts and validity", "Manage all tenant accounts and validity": "Manage all tenant accounts and validity",
"Manage machine access permissions": "Manage machine access permissions",
"Manage your catalog, prices, and multilingual details.": "Manage your catalog, prices, and multilingual details.", "Manage your catalog, prices, and multilingual details.": "Manage your catalog, prices, and multilingual details.",
"Manage your machine fleet and operational data": "Manage your machine fleet and operational data", "Manage your machine fleet and operational data": "Manage your machine fleet and operational data",
"Manage your profile information, security settings, and login history": "Manage your profile information, security settings, and login history", "Manage your profile information, security settings, and login history": "Manage your profile information, security settings, and login history",
@@ -572,6 +575,7 @@
"Scale level and access control": "層級與存取控制", "Scale level and access control": "層級與存取控制",
"Scan this code to quickly access the maintenance form for this device.": "Scan this code to quickly access the maintenance form for this device.", "Scan this code to quickly access the maintenance form for this device.": "Scan this code to quickly access the maintenance form for this device.",
"Search configurations...": "Search configurations...", "Search configurations...": "Search configurations...",
"Search company...": "Search company...",
"Search customers...": "Search customers...", "Search customers...": "Search customers...",
"Search machines by name or serial...": "Search machines by name or serial...", "Search machines by name or serial...": "Search machines by name or serial...",
"Search machines...": "Search machine name or serial...", "Search machines...": "Search machine name or serial...",
@@ -581,20 +585,21 @@
"Search serial or machine...": "Search serial or machine...", "Search serial or machine...": "Search serial or machine...",
"Search serial or name...": "Search serial or name...", "Search serial or name...": "Search serial or name...",
"Search users...": "Search users...", "Search users...": "Search users...",
"Select All": "全選", "Select All": "Select All",
"Select Company": "Select Company Name", "Select Company": "Select Company Name",
"Select Machine": "選擇機台", "Select Machine": "Select Machine",
"Select Machine to view metrics": "請選擇機台以查看指標", "Select Machine to view metrics": "Please select a machine to view metrics",
"Select Model": "Select Model", "Select Model": "Select Model",
"Select Owner": "Select Company Name", "Select Owner": "Select Company Name",
"Select a machine to deep dive": "請選擇機台以開始深度分析", "Select a machine to deep dive": "Please select a machine to deep dive",
"Select an asset from the left to start analysis": "Select an asset from the left to start analysis", "Select an asset from the left to start analysis": "Select an asset from the left to start analysis",
"Select date to sync data": "Select date to sync data", "Select date to sync data": "Select date to sync data",
"Selected": "Selected", "Selected": "Selected",
"Selected Date": "查詢日期", "Selected Date": "Search Date",
"Selection": "Selection", "Selection": "Selection",
"Serial & Version": "Serial & Version", "Serial & Version": "Serial & Version",
"Serial NO": "Serial NO", "Deselect All": "Deselect All",
"Serial NO": "SERIAL NO",
"Serial No": "Serial No", "Serial No": "Serial No",
"Serial Number": "Serial Number", "Serial Number": "Serial Number",
"Show": "Show", "Show": "Show",
@@ -652,6 +657,7 @@
"The Super Admin role is immutable.": "The Super Admin role is immutable.", "The Super Admin role is immutable.": "The Super Admin role is immutable.",
"The Super Admin role name cannot be modified.": "The Super Admin role name cannot be modified.", "The Super Admin role name cannot be modified.": "The Super Admin role name cannot be modified.",
"The image is too large. Please upload an image smaller than 1MB.": "The image is too large. Please upload an image smaller than 1MB.", "The image is too large. Please upload an image smaller than 1MB.": "The image is too large. Please upload an image smaller than 1MB.",
"This is a system administrator role. Its name is locked to ensure system stability.": "This is a system administrator role. Its name is locked to ensure system stability.",
"This role belongs to another company and cannot be assigned.": "This role belongs to another company and cannot be assigned.", "This role belongs to another company and cannot be assigned.": "This role belongs to another company and cannot be assigned.",
"Time": "Time", "Time": "Time",
"Time Slots": "Time Slots", "Time Slots": "Time Slots",
@@ -676,6 +682,7 @@
"Tutorial Page": "Tutorial Page", "Tutorial Page": "Tutorial Page",
"Type": "Type", "Type": "Type",
"UI Elements": "UI Elements", "UI Elements": "UI Elements",
"Unauthorized Status": "Unauthorized",
"Uncategorized": "Uncategorized", "Uncategorized": "Uncategorized",
"Unified Operational Timeline": "Unified Operational Timeline", "Unified Operational Timeline": "Unified Operational Timeline",
"Units": "Units", "Units": "Units",
@@ -793,11 +800,5 @@
"user": "一般用戶", "user": "一般用戶",
"vs Yesterday": "vs Yesterday", "vs Yesterday": "vs Yesterday",
"warehouses": "Warehouse Management", "warehouses": "Warehouse Management",
"待填寫": "Pending", "待填寫": "Pending"
"Authorized Accounts Tab": "Authorized Accounts",
"Authorize Btn": "Authorize",
"Authorization updated successfully": "Authorization updated successfully",
"Authorized Status": "Authorized",
"Unauthorized Status": "Unauthorized",
"This is a system administrator role. Its name is locked to ensure system stability.": "This is a system administrator role. Its name is locked to ensure system stability."
} }

View File

@@ -74,7 +74,12 @@
"Assigned Machines": "授權機台", "Assigned Machines": "授權機台",
"Audit Management": "監査管理", "Audit Management": "監査管理",
"Audit Permissions": "監査管理權限", "Audit Permissions": "監査管理權限",
"Authorization updated successfully": "認証が更新されました",
"Authorize Btn": "認可",
"Authorized Accounts Tab": "認定アカウント",
"Authorized Machines": "授權機台", "Authorized Machines": "授權機台",
"Authorized Machines Management": "認定機台管理",
"Authorized Status": "認可済み",
"Availability": "可用性 (Availability)", "Availability": "可用性 (Availability)",
"Available Machines": "可供分配的機台", "Available Machines": "可供分配的機台",
"Avatar updated successfully.": "アバターが正常に更新されました。", "Avatar updated successfully.": "アバターが正常に更新されました。",
@@ -163,7 +168,7 @@
"Customer enabled successfully.": "顧客が正常に有効化されました。", "Customer enabled successfully.": "顧客が正常に有効化されました。",
"Customer updated successfully.": "顧客が正常に更新されました。", "Customer updated successfully.": "顧客が正常に更新されました。",
"Cycle Efficiency": "サイクル効率", "Cycle Efficiency": "サイクル効率",
"Daily Revenue": "日収益", "Daily Revenue": "日収益",
"Danger Zone: Delete Account": "危険区域:アカウントの削除", "Danger Zone: Delete Account": "危険区域:アカウントの削除",
"Dashboard": "ダッシュボード", "Dashboard": "ダッシュボード",
"Data Configuration": "データ設定", "Data Configuration": "データ設定",
@@ -179,7 +184,6 @@
"Delete Product Confirmation": "商品削除の確認", "Delete Product Confirmation": "商品削除の確認",
"Deposit Bonus": "入金ボーナス", "Deposit Bonus": "入金ボーナス",
"Describe the repair or maintenance status...": "修理またはメンテナンスの状況を説明してください...", "Describe the repair or maintenance status...": "修理またはメンテナンスの状況を説明してください...",
"Deselect All": "取消全選",
"Detail": "詳細", "Detail": "詳細",
"Device Information": "デバイス情報", "Device Information": "デバイス情報",
"Device Status Logs": "デバイス状態ログ", "Device Status Logs": "デバイス状態ログ",
@@ -242,7 +246,7 @@
"Fill in the device repair or maintenance details": "デバイスの修理またはメンテナンスの詳細を入力してください", "Fill in the device repair or maintenance details": "デバイスの修理またはメンテナンスの詳細を入力してください",
"Fill in the product details below": "以下に商品の詳細を入力してください", "Fill in the product details below": "以下に商品の詳細を入力してください",
"Firmware Version": "ファームウェアバージョン", "Firmware Version": "ファームウェアバージョン",
"Fleet Avg OEE": "フリート平均 OEE", "Fleet Avg OEE": "全機台平均OEE",
"Fleet Performance": "全機隊效能", "Fleet Performance": "全機隊效能",
"From": "から", "From": "から",
"From:": "開始:", "From:": "開始:",
@@ -297,7 +301,7 @@
"Line Orders": "Line注文", "Line Orders": "Line注文",
"Line Permissions": "Line管理權限", "Line Permissions": "Line管理權限",
"Line Products": "Line商品", "Line Products": "Line商品",
"Live Fleet Updates": "ライブフリート更新", "Live Fleet Updates": "機台リアルタイム更新",
"Loading machines...": "正在載入機台...", "Loading machines...": "正在載入機台...",
"Loading...": "読み込み中...", "Loading...": "読み込み中...",
"Location": "場所", "Location": "場所",
@@ -320,8 +324,7 @@
"Machine Model Settings": "機台型號設定", "Machine Model Settings": "機台型號設定",
"Machine Name": "機台名", "Machine Name": "機台名",
"Machine Permissions": "機台権限", "Machine Permissions": "機台権限",
"Manage machine access permissions": "機台アクセス權限の管理", "Machine Registry": "機台登録簿",
"Machine Registry": "機台登録",
"Machine Reports": "機台レポート", "Machine Reports": "機台レポート",
"Machine Restart": "機台再起動", "Machine Restart": "機台再起動",
"Machine Settings": "機台設定", "Machine Settings": "機台設定",
@@ -350,6 +353,7 @@
"Manage Expiry": "進入效期管理", "Manage Expiry": "進入效期管理",
"Manage administrative and tenant accounts": "管理者およびテナントアカウントを管理します", "Manage administrative and tenant accounts": "管理者およびテナントアカウントを管理します",
"Manage all tenant accounts and validity": "すべてのテナントアカウントと有効期限を管理します", "Manage all tenant accounts and validity": "すべてのテナントアカウントと有効期限を管理します",
"Manage machine access permissions": "機台アクセス權限の管理",
"Manage your catalog, prices, and multilingual details.": "カタログ、価格、多言語詳細を管理します。", "Manage your catalog, prices, and multilingual details.": "カタログ、価格、多言語詳細を管理します。",
"Manage your machine fleet and operational data": "機台フリートと運用データの管理", "Manage your machine fleet and operational data": "機台フリートと運用データの管理",
"Manage your profile information, security settings, and login history": "プロフィール情報、セキュリティ設定、ログイン履歴の管理", "Manage your profile information, security settings, and login history": "プロフィール情報、セキュリティ設定、ログイン履歴の管理",
@@ -407,7 +411,7 @@
"No machines available in this company.": "此客戶目前沒有可供分配的機台。", "No machines available in this company.": "此客戶目前沒有可供分配的機台。",
"No maintenance records found": "メンテナンス記録が見つかりません", "No maintenance records found": "メンテナンス記録が見つかりません",
"No matching logs found": "一致するログが見つかりません", "No matching logs found": "一致するログが見つかりません",
"No matching machines": "一致する機台が見つかりません", "No matching machines": "一致する機台がりません",
"No permissions": "権限項目なし", "No permissions": "権限項目なし",
"No roles found.": "ロールが見つかりませんでした。", "No roles found.": "ロールが見つかりませんでした。",
"No slots found": "未找到貨道資訊", "No slots found": "未找到貨道資訊",
@@ -418,8 +422,8 @@
"Not Used Description": "不使用第三方支付介接", "Not Used Description": "不使用第三方支付介接",
"Notes": "備考", "Notes": "備考",
"OEE": "OEE", "OEE": "OEE",
"OEE Efficiency Trend": "OEE 効率トレンド", "OEE Efficiency Trend": "OEE効率トレンド",
"OEE Score": "OEE スコア", "OEE Score": "OEE総合スコア",
"OEE.Activity": "稼働アクティビティ", "OEE.Activity": "稼働アクティビティ",
"OEE.Errors": "エラー", "OEE.Errors": "エラー",
"OEE.Hours": "時間", "OEE.Hours": "時間",
@@ -432,12 +436,12 @@
"Online": "オンライン", "Online": "オンライン",
"Online Duration": "累積連線時數", "Online Duration": "累積連線時數",
"Online Machines": "オンライン機台", "Online Machines": "オンライン機台",
"Online Status": "オンライン状態", "Online Status": "オンラインステータス",
"Only system roles can be assigned to platform administrative accounts.": "プラットフォーム管理アカウントにはシステムロールのみ割り当て可能です。", "Only system roles can be assigned to platform administrative accounts.": "プラットフォーム管理アカウントにはシステムロールのみ割り当て可能です。",
"Operational Parameters": "運用パラメータ", "Operational Parameters": "運用パラメータ",
"Operations": "運用設定", "Operations": "運用設定",
"Optimal": "最適", "Optimal": "最適",
"Optimized Performance": "最適化されたパフォーマンス", "Optimized Performance": "パフォーマンスの最適化",
"Optimized for display. Supported formats: JPG, PNG, WebP.": "表示用に最適化されています。対応形式JPG, PNG, WebP。", "Optimized for display. Supported formats: JPG, PNG, WebP.": "表示用に最適化されています。対応形式JPG, PNG, WebP。",
"Optional": "任意", "Optional": "任意",
"Order Management": "注文管理", "Order Management": "注文管理",
@@ -447,7 +451,7 @@
"Original:": "元:", "Original:": "元:",
"Other Permissions": "其他權限", "Other Permissions": "其他權限",
"Others": "その他", "Others": "その他",
"Output Count": "出数", "Output Count": "出荷回数",
"Owner": "会社名", "Owner": "会社名",
"PARTNER_KEY": "パートナーキー", "PARTNER_KEY": "パートナーキー",
"PI_MERCHANT_ID": "Pi 拍錢包 加盟店ID", "PI_MERCHANT_ID": "Pi 拍錢包 加盟店ID",
@@ -515,9 +519,9 @@
"Quick search...": "クイック検索...", "Quick search...": "クイック検索...",
"Real-time OEE analysis awaits": "リアルタイム OEE 分析待機中", "Real-time OEE analysis awaits": "リアルタイム OEE 分析待機中",
"Real-time Operation Logs (Last 50)": "リアルタイム操作ログ (直近 50 件)", "Real-time Operation Logs (Last 50)": "リアルタイム操作ログ (直近 50 件)",
"Real-time fleet efficiency and OEE metrics": "リアルタイムのフリート効率と OEE 指標", "Real-time fleet efficiency and OEE metrics": "全機台リアルタイム効率とOEE指標",
"Real-time monitoring across all machines": "全機台のリアルタイム監視", "Real-time monitoring across all machines": "全機台のリアルタイム監視",
"Real-time performance analytics": "リアルタイムパフォーマンス分析", "Real-time performance analytics": "リアルタイムパフォーマンス分析",
"Real-time status monitoring": "リアルタイムステータス監視", "Real-time status monitoring": "リアルタイムステータス監視",
"Receipt Printing": "レシート印刷", "Receipt Printing": "レシート印刷",
"Recent Login": "最近のログイン", "Recent Login": "最近のログイン",
@@ -572,6 +576,7 @@
"Scale level and access control": "層級與存取控制", "Scale level and access control": "層級與存取控制",
"Scan this code to quickly access the maintenance form for this device.": "このコードをスキャンして、このデバイスのメンテナンスフォームに素早くアクセスしてください。", "Scan this code to quickly access the maintenance form for this device.": "このコードをスキャンして、このデバイスのメンテナンスフォームに素早くアクセスしてください。",
"Search configurations...": "設定を検索...", "Search configurations...": "設定を検索...",
"Search company...": "会社を検索...",
"Search customers...": "顧客を検索...", "Search customers...": "顧客を検索...",
"Search machines by name or serial...": "名称またはシリアル番号で検索...", "Search machines by name or serial...": "名称またはシリアル番号で検索...",
"Search machines...": "マシン名またはシリアル番号で検索...", "Search machines...": "マシン名またはシリアル番号で検索...",
@@ -579,22 +584,23 @@
"Search roles...": "ロールを検索...", "Search roles...": "ロールを検索...",
"Search serial no or name...": "シリアル番号または名前を検索...", "Search serial no or name...": "シリアル番号または名前を検索...",
"Search serial or machine...": "シリアルまたはマシンを検索...", "Search serial or machine...": "シリアルまたはマシンを検索...",
"Search serial or name...": "シリアル番号または名称で検索...", "Search serial or name...": "機台名またはシリアル番号で検索...",
"Search users...": "ユーザーを検索...", "Search users...": "ユーザーを検索...",
"Select All": "全選", "Select All": "すべて選択",
"Select Company": "会社名を選択", "Select Company": "会社名を選択",
"Select Machine": "選擇機台", "Select Machine": "機台を選択",
"Select Machine to view metrics": "請選擇機台以查看指標", "Select Machine to view metrics": "指標を表示する機台を選択してください",
"Select Model": "型番を選択", "Select Model": "型番を選択",
"Select Owner": "会社名を選択", "Select Owner": "会社名を選択",
"Select a machine to deep dive": "請選擇機台以開始深度分析", "Select a machine to deep dive": "詳細分析を開始する機台を選択してください",
"Select an asset from the left to start analysis": "分析を開始するには左側のデバイスを選択してください", "Select an asset from the left to start analysis": "分析を開始するには左側のデバイスを選択してください",
"Select date to sync data": "データ同期の日付を選択してください", "Select date to sync data": "データ同期の日付を選択してください",
"Selected": "已選擇", "Selected": "選択済み",
"Selected Date": "查詢日期", "Selected Date": "検索日",
"Selection": "選択済み", "Selection": "選択済み",
"Deselect All": "すべて選択解除",
"Serial & Version": "シリアルとバージョン", "Serial & Version": "シリアルとバージョン",
"Serial NO": "シリアル番号", "Serial NO": "機台シリアル番号",
"Serial No": "機台シリアル番号", "Serial No": "機台シリアル番号",
"Serial Number": "シリアル番号", "Serial Number": "シリアル番号",
"Show": "表示", "Show": "表示",
@@ -654,6 +660,7 @@
"The Super Admin role is immutable.": "スーパー管理者ロールは変更できません。", "The Super Admin role is immutable.": "スーパー管理者ロールは変更できません。",
"The Super Admin role name cannot be modified.": "スーパー管理者のロール名は変更できません。", "The Super Admin role name cannot be modified.": "スーパー管理者のロール名は変更できません。",
"The image is too large. Please upload an image smaller than 1MB.": "画像が大きすぎます。1MB未満の画像をアップロードしてください。", "The image is too large. Please upload an image smaller than 1MB.": "画像が大きすぎます。1MB未満の画像をアップロードしてください。",
"This is a system administrator role. Its name is locked to ensure system stability.": "これはシステム管理者ロールです。システムの安定性を確保するため、名称は固定されています。",
"This role belongs to another company and cannot be assigned.": "このロールは他の会社に属しており、割り当てることはできません。", "This role belongs to another company and cannot be assigned.": "このロールは他の会社に属しており、割り当てることはできません。",
"Time": "時間", "Time": "時間",
"Time Slots": "タイムスロット", "Time Slots": "タイムスロット",
@@ -665,7 +672,7 @@
"Total Connected": "接続数合計", "Total Connected": "接続数合計",
"Total Customers": "顧客總數", "Total Customers": "顧客總數",
"Total Daily Sales": "本日累計銷量", "Total Daily Sales": "本日累計銷量",
"Total Gross Value": "売上", "Total Gross Value": "売上高計",
"Total Logins": "總ログイン數", "Total Logins": "總ログイン數",
"Total Selected": "已選擇總數", "Total Selected": "已選擇總數",
"Total Slots": "合計スロット数", "Total Slots": "合計スロット数",
@@ -678,9 +685,10 @@
"Tutorial Page": "チュートリアル画面", "Tutorial Page": "チュートリアル画面",
"Type": "タイプ", "Type": "タイプ",
"UI Elements": "UI要素", "UI Elements": "UI要素",
"Unauthorized Status": "未認可",
"Uncategorized": "未分類", "Uncategorized": "未分類",
"Unified Operational Timeline": "整合式營運時序圖", "Unified Operational Timeline": "整合式營運時序圖",
"Units": "ユニット", "Units": "",
"Unknown": "不明", "Unknown": "不明",
"Update": "更新", "Update": "更新",
"Update Authorization": "権限を更新", "Update Authorization": "権限を更新",
@@ -698,7 +706,7 @@
"Utilization Rate": "稼働率", "Utilization Rate": "稼働率",
"Utilization Timeline": "稼動時序", "Utilization Timeline": "稼動時序",
"Utilization, OEE and Operational Intelligence": "稼動率、OEE と運用インテリジェンス", "Utilization, OEE and Operational Intelligence": "稼動率、OEE と運用インテリジェンス",
"Utilized Time": "稼時間", "Utilized Time": "稼動持続時間",
"Valid Until": "有効期限", "Valid Until": "有効期限",
"Validation Error": "検証エラー", "Validation Error": "検証エラー",
"Vending Page": "販売画面", "Vending Page": "販売画面",
@@ -795,12 +803,5 @@
"user": "一般用戶", "user": "一般用戶",
"vs Yesterday": "前日比", "vs Yesterday": "前日比",
"warehouses": "倉庫管理", "warehouses": "倉庫管理",
"待填寫": "待填寫", "待填寫": "待填寫"
"Authorized Accounts Tab": "認定アカウント",
"Authorize Btn": "認可",
"Authorized Machines Management": "認定機台管理",
"Authorization updated successfully": "認証が更新されました",
"Authorized Status": "認可済み",
"Unauthorized Status": "未認可",
"This is a system administrator role. Its name is locked to ensure system stability.": "これはシステム管理者ロールです。システムの安定性を確保するため、名称は固定されています。"
} }

View File

@@ -77,10 +77,14 @@
"Assigned Machines": "授權機台", "Assigned Machines": "授權機台",
"Audit Management": "稽核管理", "Audit Management": "稽核管理",
"Audit Permissions": "稽核管理權限", "Audit Permissions": "稽核管理權限",
"Authorization updated successfully": "授權更新成功",
"Authorize": "授權", "Authorize": "授權",
"Authorize Btn": "授權",
"Authorized Accounts": "授權帳號", "Authorized Accounts": "授權帳號",
"Authorized Accounts Tab": "授權帳號",
"Authorized Machines": "授權機台", "Authorized Machines": "授權機台",
"Authorized Machines Management": "授權機台管理", "Authorized Machines Management": "授權機台管理",
"Authorized Status": "已授權",
"Availability": "可用性 (Availability)", "Availability": "可用性 (Availability)",
"Available Machines": "可供分配的機台", "Available Machines": "可供分配的機台",
"Avatar updated successfully.": "頭像已成功更新。", "Avatar updated successfully.": "頭像已成功更新。",
@@ -189,7 +193,6 @@
"Delete Product Confirmation": "刪除商品確認", "Delete Product Confirmation": "刪除商品確認",
"Deposit Bonus": "儲值回饋", "Deposit Bonus": "儲值回饋",
"Describe the repair or maintenance status...": "請描述維修或保養狀況...", "Describe the repair or maintenance status...": "請描述維修或保養狀況...",
"Deselect All": "取消全選",
"Detail": "詳細", "Detail": "詳細",
"Device Information": "設備資訊", "Device Information": "設備資訊",
"Device Status Logs": "設備狀態紀錄", "Device Status Logs": "設備狀態紀錄",
@@ -322,7 +325,7 @@
"Machine Details": "機台詳情", "Machine Details": "機台詳情",
"Machine Images": "機台照片", "Machine Images": "機台照片",
"Machine Info": "機台資訊", "Machine Info": "機台資訊",
"Machine Information": "機資訊", "Machine Information": "機資訊",
"Machine List": "機台列表", "Machine List": "機台列表",
"Machine Login Logs": "機台登入紀錄", "Machine Login Logs": "機台登入紀錄",
"Machine Logs": "機台日誌", "Machine Logs": "機台日誌",
@@ -332,7 +335,6 @@
"Machine Model Settings": "機台型號設定", "Machine Model Settings": "機台型號設定",
"Machine Name": "機台名稱", "Machine Name": "機台名稱",
"Machine Permissions": "機台權限", "Machine Permissions": "機台權限",
"Manage machine access permissions": "管理機台存取權限",
"Machine Registry": "機台清冊", "Machine Registry": "機台清冊",
"Machine Reports": "機台報表", "Machine Reports": "機台報表",
"Machine Restart": "機台重啟", "Machine Restart": "機台重啟",
@@ -362,6 +364,7 @@
"Manage Expiry": "進入效期管理", "Manage Expiry": "進入效期管理",
"Manage administrative and tenant accounts": "管理系統管理者與租戶帳號", "Manage administrative and tenant accounts": "管理系統管理者與租戶帳號",
"Manage all tenant accounts and validity": "管理所有租戶帳號與合約效期", "Manage all tenant accounts and validity": "管理所有租戶帳號與合約效期",
"Manage machine access permissions": "管理機台存取權限",
"Manage your catalog, prices, and multilingual details.": "管理您的商品型錄、價格及多語系詳情。", "Manage your catalog, prices, and multilingual details.": "管理您的商品型錄、價格及多語系詳情。",
"Manage your machine fleet and operational data": "管理您的機台群組與營運數據", "Manage your machine fleet and operational data": "管理您的機台群組與營運數據",
"Manage your profile information, security settings, and login history": "管理您的個人資訊、安全設定與登入紀錄", "Manage your profile information, security settings, and login history": "管理您的個人資訊、安全設定與登入紀錄",
@@ -421,7 +424,7 @@
"No machines available in this company.": "此客戶目前沒有可供分配的機台。", "No machines available in this company.": "此客戶目前沒有可供分配的機台。",
"No maintenance records found": "找不到維修紀錄", "No maintenance records found": "找不到維修紀錄",
"No matching logs found": "找不到符合條件的日誌", "No matching logs found": "找不到符合條件的日誌",
"No matching machines": "找不到符合的機台", "No matching machines": "查無匹配機台",
"No permissions": "無權限項目", "No permissions": "無權限項目",
"No roles found.": "找不到角色資料。", "No roles found.": "找不到角色資料。",
"No slots found": "未找到貨道資訊", "No slots found": "未找到貨道資訊",
@@ -432,7 +435,7 @@
"Not Used Description": "不使用第三方支付介接", "Not Used Description": "不使用第三方支付介接",
"Notes": "備註", "Notes": "備註",
"OEE Efficiency Trend": "OEE 效率趨勢", "OEE Efficiency Trend": "OEE 效率趨勢",
"OEE Score": "OEE 綜合分", "OEE Score": "OEE 綜合分",
"OEE.Activity": "營運活動", "OEE.Activity": "營運活動",
"OEE.Errors": "異常", "OEE.Errors": "異常",
"OEE.Hours": "小時", "OEE.Hours": "小時",
@@ -450,7 +453,7 @@
"Operational Parameters": "運作參數", "Operational Parameters": "運作參數",
"Operations": "運作設定", "Operations": "運作設定",
"Optimal": "良好", "Optimal": "良好",
"Optimized Performance": "效能化", "Optimized Performance": "效能最佳化",
"Optimized for display. Supported formats: JPG, PNG, WebP.": "已針對顯示進行優化。支援格式JPG, PNG, WebP。", "Optimized for display. Supported formats: JPG, PNG, WebP.": "已針對顯示進行優化。支援格式JPG, PNG, WebP。",
"Optional": "選填", "Optional": "選填",
"Order Management": "訂單管理", "Order Management": "訂單管理",
@@ -460,7 +463,7 @@
"Original:": "原:", "Original:": "原:",
"Other Permissions": "其他權限", "Other Permissions": "其他權限",
"Others": "其他功能", "Others": "其他功能",
"Output Count": "出貨數", "Output Count": "出貨數",
"Owner": "公司名稱", "Owner": "公司名稱",
"PARTNER_KEY": "PARTNER_KEY", "PARTNER_KEY": "PARTNER_KEY",
"PI_MERCHANT_ID": "Pi 拍錢包 商店代號", "PI_MERCHANT_ID": "Pi 拍錢包 商店代號",
@@ -589,6 +592,7 @@
"Scale level and access control": "層級與存取控制", "Scale level and access control": "層級與存取控制",
"Scan this code to quickly access the maintenance form for this device.": "掃描此 QR Code 即可快速進入此設備的維修單填寫頁面。", "Scan this code to quickly access the maintenance form for this device.": "掃描此 QR Code 即可快速進入此設備的維修單填寫頁面。",
"Search accounts...": "搜尋帳號...", "Search accounts...": "搜尋帳號...",
"Search company...": "搜尋公司...",
"Search configurations...": "搜尋設定...", "Search configurations...": "搜尋設定...",
"Search customers...": "搜尋客戶...", "Search customers...": "搜尋客戶...",
"Search machines by name or serial...": "搜尋機台名稱或序號...", "Search machines by name or serial...": "搜尋機台名稱或序號...",
@@ -598,6 +602,7 @@
"Search roles...": "搜尋角色...", "Search roles...": "搜尋角色...",
"Search serial no or name...": "搜尋序號或機台名稱...", "Search serial no or name...": "搜尋序號或機台名稱...",
"Search serial or machine...": "搜尋序號或機台名稱...", "Search serial or machine...": "搜尋序號或機台名稱...",
"Search serial or name...": "搜尋序號或機台名稱...",
"Search users...": "搜尋用戶...", "Search users...": "搜尋用戶...",
"Select All": "全選", "Select All": "全選",
"Select Category": "選擇類別", "Select Category": "選擇類別",
@@ -607,11 +612,14 @@
"Select Model": "選擇型號", "Select Model": "選擇型號",
"Select Owner": "選擇公司名稱", "Select Owner": "選擇公司名稱",
"Select a machine to deep dive": "請選擇機台以開始深度分析", "Select a machine to deep dive": "請選擇機台以開始深度分析",
"Select an asset from the left to start analysis": "選擇左側機台以開始分析數據",
"Select date to sync data": "選擇日期以同步數據", "Select date to sync data": "選擇日期以同步數據",
"Selected": "已選擇", "Selected": "已選擇",
"Selected Date": "查詢日期", "Selected Date": "查詢日期",
"Selection": "已選擇", "Selection": "已選擇",
"Serial & Version": "序號與版本", "Serial & Version": "序號與版本",
"Deselect All": "取消全選",
"Serial NO": "機台序號",
"Serial No": "機台序號", "Serial No": "機台序號",
"Serial Number": "機台序號", "Serial Number": "機台序號",
"Show": "顯示", "Show": "顯示",
@@ -674,6 +682,7 @@
"The Super Admin role is immutable.": "超級管理員角色不可修改。", "The Super Admin role is immutable.": "超級管理員角色不可修改。",
"The Super Admin role name cannot be modified.": "超級管理員角色的名稱無法修改。", "The Super Admin role name cannot be modified.": "超級管理員角色的名稱無法修改。",
"The image is too large. Please upload an image smaller than 1MB.": "圖片檔案太大,請上傳小於 1MB 的圖片。", "The image is too large. Please upload an image smaller than 1MB.": "圖片檔案太大,請上傳小於 1MB 的圖片。",
"This is a system administrator role. Its name is locked to ensure system stability.": "這是系統管理員角色,名稱已鎖定以確保系統穩定性。",
"This role belongs to another company and cannot be assigned.": "此角色屬於其他公司,無法指派。", "This role belongs to another company and cannot be assigned.": "此角色屬於其他公司,無法指派。",
"Time": "時間", "Time": "時間",
"Time Slots": "時段組合", "Time Slots": "時段組合",
@@ -686,7 +695,7 @@
"Total Connected": "總計連線數", "Total Connected": "總計連線數",
"Total Customers": "客戶總數", "Total Customers": "客戶總數",
"Total Daily Sales": "本日累計銷量", "Total Daily Sales": "本日累計銷量",
"Total Gross Value": "銷售總", "Total Gross Value": "銷售總",
"Total Logins": "總登入次數", "Total Logins": "總登入次數",
"Total Selected": "已選擇總數", "Total Selected": "已選擇總數",
"Total Slots": "總貨道數", "Total Slots": "總貨道數",
@@ -700,6 +709,7 @@
"Tutorial Page": "教學頁", "Tutorial Page": "教學頁",
"Type": "類型", "Type": "類型",
"UI Elements": "UI元素", "UI Elements": "UI元素",
"Unauthorized Status": "未授權",
"Uncategorized": "未分類", "Uncategorized": "未分類",
"Unified Operational Timeline": "整合式營運時序圖", "Unified Operational Timeline": "整合式營運時序圖",
"Units": "台", "Units": "台",
@@ -818,11 +828,5 @@
"user": "一般用戶", "user": "一般用戶",
"vs Yesterday": "較昨日", "vs Yesterday": "較昨日",
"warehouses": "倉庫管理", "warehouses": "倉庫管理",
"待填寫": "待填寫", "待填寫": "待填寫"
"Authorized Accounts Tab": "授權帳號",
"Authorize Btn": "授權",
"Authorization updated successfully": "授權更新成功",
"Authorized Status": "已授權",
"Unauthorized Status": "未授權",
"This is a system administrator role. Its name is locked to ensure system stability.": "這是系統管理員角色,名稱已鎖定以確保系統穩定性。"
} }

View File

@@ -42,6 +42,16 @@
togglePermission(machineId) { togglePermission(machineId) {
this.permissions = { ...this.permissions, [machineId]: !this.permissions[machineId] }; this.permissions = { ...this.permissions, [machineId]: !this.permissions[machineId] };
}, },
toggleSelectAll() {
const filtered = this.allMachines.filter(m =>
!this.permissionSearchQuery ||
m.name.toLowerCase().includes(this.permissionSearchQuery.toLowerCase()) ||
m.serial_no.toLowerCase().includes(this.permissionSearchQuery.toLowerCase())
);
if (filtered.length === 0) return;
const allSelected = filtered.every(m => this.permissions[m.id]);
filtered.forEach(m => this.permissions[m.id] = !allSelected);
},
savePermissions() { savePermissions() {
const machineIds = Object.keys(this.permissions).filter(id => this.permissions[id]); const machineIds = Object.keys(this.permissions).filter(id => this.permissions[id]);
@@ -80,19 +90,29 @@
<!-- 2. Main Content Card --> <!-- 2. Main Content Card -->
<div class="luxury-card rounded-3xl p-8 animate-luxury-in"> <div class="luxury-card rounded-3xl p-8 animate-luxury-in">
<!-- Toolbar & Filters --> <!-- Toolbar & Filters -->
<div class="flex items-center justify-between mb-8"> <div class="flex flex-col md:flex-row items-center justify-between mb-8 gap-4">
<form method="GET" action="{{ route('admin.machines.permissions') }}" class="relative group"> <form method="GET" action="{{ route('admin.machines.permissions') }}"
<span class="absolute inset-y-0 left-0 flex items-center pl-4 pointer-events-none z-10"> class="flex flex-wrap items-center gap-4 w-full md:w-auto">
<svg class="h-4 w-4 text-slate-400 group-focus-within:text-cyan-500 transition-colors" <div class="relative group">
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" <span class="absolute inset-y-0 left-0 flex items-center pl-4 pointer-events-none z-10">
stroke-linejoin="round"> <svg class="h-4 w-4 text-slate-400 group-focus-within:text-cyan-500 transition-colors"
<circle cx="11" cy="11" r="8"></circle> viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
<line x1="21" y1="21" x2="16.65" y2="16.65"></line> stroke-linecap="round" stroke-linejoin="round">
</svg> <circle cx="11" cy="11" r="8"></circle>
</span> <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
<input type="text" name="search" value="{{ request('search') }}" </svg>
placeholder="{{ __('Search accounts...') }}" </span>
class="luxury-input py-2.5 pl-12 pr-6 block w-64"> <input type="text" name="search" value="{{ request('search') }}"
placeholder="{{ __('Search accounts...') }}"
class="luxury-input py-2.5 pl-12 pr-6 block w-64 text-sm font-bold">
</div>
@if(auth()->user()->isSystemAdmin())
<div class="w-72">
<x-searchable-select name="company_id" :options="$companies" :selected="request('company_id')"
:placeholder="__('All Companies')" onchange="this.form.submit()" />
</div>
@endif
</form> </form>
</div> </div>
@@ -100,13 +120,17 @@
<table class="w-full text-left border-separate border-spacing-y-0"> <table class="w-full text-left border-separate border-spacing-y-0">
<thead> <thead>
<tr class="bg-slate-50/50 dark:bg-slate-900/10"> <tr class="bg-slate-50/50 dark:bg-slate-900/10">
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800"> <th
class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">
{{ __('Account Info') }}</th> {{ __('Account Info') }}</th>
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800"> <th
class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">
{{ __('Company Name') }}</th> {{ __('Company Name') }}</th>
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-center"> <th
class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-center">
{{ __('Authorized Machines') }}</th> {{ __('Authorized Machines') }}</th>
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-right"> <th
class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-right">
{{ __('Action') }}</th> {{ __('Action') }}</th>
</tr> </tr>
</thead> </thead>
@@ -115,40 +139,57 @@
<tr class="group hover:bg-slate-50/80 dark:hover:bg-slate-800/40 transition-all duration-300"> <tr class="group hover:bg-slate-50/80 dark:hover:bg-slate-800/40 transition-all duration-300">
<td class="px-6 py-6 font-display"> <td class="px-6 py-6 font-display">
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
<div class="w-10 h-10 rounded-xl bg-slate-100 dark:bg-slate-800 flex items-center justify-center text-slate-400 border border-slate-200 dark:border-slate-700"> <div
class="w-10 h-10 rounded-xl bg-slate-100 dark:bg-slate-800 flex items-center justify-center text-slate-400 border border-slate-200 dark:border-slate-700">
<svg class="size-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="size-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5"
d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z" />
</svg> </svg>
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
<span class="text-base font-extrabold text-slate-800 dark:text-slate-100 group-hover:text-cyan-600 dark:group-hover:text-cyan-400 transition-colors">{{ $user->name }}</span> <span
<span class="text-xs font-mono font-bold text-slate-500 tracking-widest uppercase">{{ $user->username }}</span> class="text-base font-extrabold text-slate-800 dark:text-slate-100 group-hover:text-cyan-600 dark:group-hover:text-cyan-400 transition-colors">{{
$user->name }}</span>
<span
class="text-xs font-mono font-bold text-slate-500 tracking-widest uppercase">{{
$user->username }}</span>
</div> </div>
</div> </div>
</td> </td>
<td class="px-6 py-6"> <td class="px-6 py-6">
<span class="px-2.5 py-1 rounded-lg text-xs font-bold border border-sky-100 dark:border-sky-900/30 bg-sky-50 dark:bg-sky-900/20 text-sky-600 dark:text-sky-400 tracking-widest uppercase"> <span
class="px-2.5 py-1 rounded-lg text-xs font-bold border border-sky-100 dark:border-sky-900/30 bg-sky-50 dark:bg-sky-900/20 text-sky-600 dark:text-sky-400 tracking-widest uppercase">
{{ $user->company->name ?? __('System') }} {{ $user->company->name ?? __('System') }}
</span> </span>
</td> </td>
<td class="px-6 py-6"> <td class="px-6 py-4">
<div class="flex flex-wrap gap-2 justify-center lg:justify-start max-w-[400px] mx-auto lg:mx-0"> <div
class="flex flex-wrap gap-2 justify-center lg:justify-start max-w-[420px] mx-auto lg:mx-0 max-h-[140px] overflow-y-auto pr-2 custom-scrollbar py-1">
@forelse($user->machines as $m) @forelse($user->machines as $m)
<div class="flex flex-col px-4 py-2.5 rounded-xl bg-slate-50 dark:bg-slate-800/40 border border-slate-100 dark:border-white/5 hover:border-cyan-500/30 transition-all duration-300 shadow-sm"> <div
<span class="text-xs font-black text-slate-700 dark:text-slate-200 leading-tight">{{ $m->name }}</span> class="flex flex-col px-3 py-1.5 rounded-xl bg-slate-50 dark:bg-slate-800/40 border border-slate-100 dark:border-white/5 hover:border-cyan-500/30 transition-all duration-300">
<span class="text-[10px] font-mono font-bold text-cyan-500 tracking-tighter mt-1">{{ $m->serial_no }}</span> <span class="text-[11px] font-black text-slate-700 dark:text-slate-200 leading-tight">{{
</div> $m->name }}</span>
<span class="text-[9px] font-mono font-bold text-cyan-500 tracking-tighter mt-0.5 opacity-80">{{
$m->serial_no }}</span>
</div>
@empty @empty
<div class="w-full text-center lg:text-left"> <div class="w-full text-center lg:text-left">
<span class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest opacity-40 italic">-- {{ __('None') }} --</span> <span
</div> class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest opacity-40 italic">--
{{ __('None') }} --</span>
</div>
@endforelse @endforelse
</div> </div>
</td> </td>
<td class="px-6 py-6 text-right"> <td class="px-6 py-6 text-right">
<button @click="openPermissionModal({{ json_encode(['id' => $user->id, 'name' => $user->name]) }})" <button
class="inline-flex items-center gap-2 px-4 py-2 rounded-xl bg-cyan-500/10 text-cyan-600 dark:text-cyan-400 hover:bg-cyan-500 hover:text-white transition-all duration-300 text-xs font-black uppercase tracking-widest shadow-sm shadow-cyan-500/5 group/auth"> @click="openPermissionModal({{ json_encode(['id' => $user->id, 'name' => $user->name]) }})"
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 00-2 2zm10-10V7a4 4 0 00-8 0v4h8z" /></svg> class="inline-flex items-center gap-2 px-4 py-2 rounded-xl bg-cyan-500/10 text-cyan-600 dark:text-cyan-400 hover:bg-cyan-500 hover:text-white transition-all duration-300 text-xs font-black uppercase tracking-widest shadow-sm shadow-cyan-500/5 group/auth">
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5"
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 00-2 2zm10-10V7a4 4 0 00-8 0v4h8z" />
</svg>
<span>{{ __('Authorize') }}</span> <span>{{ __('Authorize') }}</span>
</button> </button>
</td> </td>
@@ -157,8 +198,12 @@
<tr> <tr>
<td colspan="4" class="px-6 py-24 text-center"> <td colspan="4" class="px-6 py-24 text-center">
<div class="flex flex-col items-center gap-3 opacity-20"> <div class="flex flex-col items-center gap-3 opacity-20">
<svg class="size-16" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2m16-10a4 4 0 11-8 0 4 4 0 018 0zM23 21v-2a4 4 0 00-3-3.87m-4-12a4 4 0 010 7.75" /></svg> <svg class="size-16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<p class="text-slate-400 font-extrabold tracking-widest uppercase text-xs">{{ __('No accounts found') }}</p> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2m16-10a4 4 0 11-8 0 4 4 0 018 0zM23 21v-2a4 4 0 00-3-3.87m-4-12a4 4 0 010 7.75" />
</svg>
<p class="text-slate-400 font-extrabold tracking-widest uppercase text-xs">{{ __('No
accounts found') }}</p>
</div> </div>
</td> </td>
</tr> </tr>
@@ -183,8 +228,7 @@
<span class='hidden sm:inline-block sm:align-middle sm:h-screen'>&#8203;</span> <span class='hidden sm:inline-block sm:align-middle sm:h-screen'>&#8203;</span>
<div x-show='showPermissionModal' <div x-show='showPermissionModal' x-transition:enter='ease-out duration-300'
x-transition:enter='ease-out duration-300'
x-transition:enter-start='opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95' x-transition:enter-start='opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95'
x-transition:enter-end='opacity-100 translate-y-0 sm:scale-100' x-transition:enter-end='opacity-100 translate-y-0 sm:scale-100'
x-transition:leave='ease-in duration-200' x-transition:leave='ease-in duration-200'
@@ -194,62 +238,101 @@
<div class='flex justify-between items-center mb-8'> <div class='flex justify-between items-center mb-8'>
<div> <div>
<h3 class='text-2xl font-black text-slate-800 dark:text-white font-display tracking-tight'>{{ __('Authorized Machines Management') }}</h3> <h3 class='text-2xl font-black text-slate-800 dark:text-white font-display tracking-tight'>
{{ __('Authorized Machines Management') }}</h3>
<div class='flex items-center gap-2 mt-1'> <div class='flex items-center gap-2 mt-1'>
<span class='text-[10px] font-black text-slate-400 uppercase tracking-[0.2em]'>{{ __('Account') }}:</span> <span class='text-[10px] font-black text-slate-400 uppercase tracking-[0.2em]'>{{
<span class='text-xs font-bold text-cyan-500 uppercase tracking-widest' x-text='targetUserName'></span> __('Account') }}:</span>
<span class='text-xs font-bold text-cyan-500 uppercase tracking-widest'
x-text='targetUserName'></span>
</div> </div>
</div> </div>
<button @click='showPermissionModal = false' class='text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 transition-colors bg-slate-50 dark:bg-slate-800 p-2 rounded-xl'> <button @click='showPermissionModal = false'
<svg class='size-6' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2.5' d='M6 18L18 6M6 6l12 12' /></svg> class='text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 transition-colors bg-slate-50 dark:bg-slate-800 p-2 rounded-xl'>
<svg class='size-6' fill='none' stroke='currentColor' viewBox='0 0 24 24'>
<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2.5'
d='M6 18L18 6M6 6l12 12' />
</svg>
</button> </button>
</div> </div>
<div class='relative min-h-[400px]'> <div class='relative min-h-[400px]'>
<div class='mb-6'> <div class='mb-6 flex flex-col md:flex-row gap-4 items-center'>
<div class='relative group'> <div class='flex-1 relative group w-full'>
<span class='absolute inset-y-0 left-0 flex items-center pl-4 pointer-events-none z-10'> <span class='absolute inset-y-0 left-0 flex items-center pl-4 pointer-events-none z-10'>
<svg class='size-4 text-slate-400 group-focus-within:text-cyan-500 transition-colors' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'> <svg class='size-4 text-slate-400 group-focus-within:text-cyan-500 transition-colors'
viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5'
stroke-linecap='round' stroke-linejoin='round'>
<circle cx='11' cy='11' r='8'></circle> <circle cx='11' cy='11' r='8'></circle>
<line x1='21' y1='21' x2='16.65' y2='16.65'></line> <line x1='21' y1='21' x2='16.65' y2='16.65'></line>
</svg> </svg>
</span> </span>
<input type='text' x-model='permissionSearchQuery' placeholder='{{ __("Search machines...") }}' <input type='text' x-model='permissionSearchQuery'
class='luxury-input py-3 pl-12 pr-6 block w-full text-sm' @click.stop> placeholder='{{ __("Search machines...") }}'
class='luxury-input py-3 pl-12 pr-6 block w-full text-sm font-bold' @click.stop>
</div> </div>
<button @click="toggleSelectAll()"
class="shrink-0 flex items-center gap-2 px-6 py-3 rounded-xl bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300 hover:bg-cyan-500 hover:text-white transition-all duration-300 border border-slate-200 dark:border-slate-700 font-black text-xs uppercase tracking-widest">
<svg class="size-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5"
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
</svg>
<span
x-text="allMachines.filter(m => !permissionSearchQuery || m.name.toLowerCase().includes(permissionSearchQuery.toLowerCase()) || m.serial_no.toLowerCase().includes(permissionSearchQuery.toLowerCase())).every(m => permissions[m.id]) ? '{{ __('Deselect All') }}' : '{{ __('Select All') }}'"></span>
</button>
</div> </div>
<template x-if='isPermissionsLoading'> <template x-if='isPermissionsLoading'>
<div class='absolute inset-0 flex items-center justify-center bg-white/50 dark:bg-slate-900/50 backdrop-blur-sm z-10 rounded-2xl'> <div
class='absolute inset-0 flex items-center justify-center bg-white/50 dark:bg-slate-900/50 backdrop-blur-sm z-10 rounded-2xl'>
<div class='flex flex-col items-center gap-3'> <div class='flex flex-col items-center gap-3'>
<div class='w-10 h-10 border-4 border-cyan-500/20 border-t-cyan-500 rounded-full animate-spin'></div> <div
<span class='text-[10px] font-black text-cyan-600 dark:text-cyan-400 uppercase tracking-[0.2em] animate-pulse'>{{ __('Syncing Permissions...') }}</span> class='w-10 h-10 border-4 border-cyan-500/20 border-t-cyan-500 rounded-full animate-spin'>
</div>
<span
class='text-[10px] font-black text-cyan-600 dark:text-cyan-400 uppercase tracking-[0.2em] animate-pulse'>{{
__('Syncing Permissions...') }}</span>
</div> </div>
</div> </div>
</template> </template>
<div class='grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 max-h-[450px] overflow-y-auto pr-2 custom-scrollbar p-1'> <div
<template x-for='machine in allMachines.filter(m => !permissionSearchQuery || m.name.toLowerCase().includes(permissionSearchQuery.toLowerCase()) || m.serial_no.toLowerCase().includes(permissionSearchQuery.toLowerCase()))' :key='machine.id'> class='grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 max-h-[450px] overflow-y-auto pr-2 custom-scrollbar p-1'>
<template
x-for='machine in allMachines.filter(m => !permissionSearchQuery || m.name.toLowerCase().includes(permissionSearchQuery.toLowerCase()) || m.serial_no.toLowerCase().includes(permissionSearchQuery.toLowerCase()))'
:key='machine.id'>
<div @click='togglePermission(machine.id)' <div @click='togglePermission(machine.id)'
:class='permissions[machine.id] ? "border-cyan-500 bg-cyan-500/5 dark:bg-cyan-500/10 ring-1 ring-cyan-500/20" : "border-slate-100 dark:border-slate-800 hover:border-slate-300 dark:hover:border-slate-600"' :class='permissions[machine.id] ? "border-cyan-500 bg-cyan-500/5 dark:bg-cyan-500/10 ring-1 ring-cyan-500/20" : "border-slate-100 dark:border-slate-800 hover:border-slate-300 dark:hover:border-slate-600"'
class='p-4 rounded-2xl border-2 cursor-pointer transition-all duration-300 group relative overflow-hidden shadow-sm hover:shadow-md'> class='p-4 rounded-2xl border-2 cursor-pointer transition-all duration-300 group relative overflow-hidden shadow-sm hover:shadow-md'>
<div class='flex flex-col relative z-10'> <div class='flex flex-col relative z-10'>
<div class='flex items-center gap-2'> <div class='flex items-center gap-2'>
<div class='size-2 rounded-full' :class='permissions[machine.id] ? "bg-cyan-500" : "bg-slate-300 dark:bg-slate-700"'></div> <div class='size-2 rounded-full'
<span class='text-sm font-extrabold truncate' :class='permissions[machine.id] ? "text-cyan-600 dark:text-cyan-400" : "text-slate-700 dark:text-slate-300"' :class='permissions[machine.id] ? "bg-cyan-500" : "bg-slate-300 dark:bg-slate-700"'>
</div>
<span class='text-sm font-extrabold truncate'
:class='permissions[machine.id] ? "text-cyan-600 dark:text-cyan-400" : "text-slate-700 dark:text-slate-300"'
x-text='machine.name'></span> x-text='machine.name'></span>
</div> </div>
<span class='text-[10px] font-mono font-bold text-slate-400 mt-2 tracking-widest uppercase' <span
class='text-[10px] font-mono font-bold text-slate-400 mt-2 tracking-widest uppercase'
x-text='machine.serial_no'></span> x-text='machine.serial_no'></span>
</div> </div>
<div class='absolute -right-2 -bottom-2 opacity-[0.03] text-slate-900 dark:text-white pointer-events-none group-hover:scale-110 transition-transform duration-700'> <div
class='absolute -right-2 -bottom-2 opacity-[0.03] text-slate-900 dark:text-white pointer-events-none group-hover:scale-110 transition-transform duration-700'>
<svg class='size-20' fill='currentColor' viewBox='0 0 24 24'> <svg class='size-20' fill='currentColor' viewBox='0 0 24 24'>
<path d='M5 2h14c1.1 0 2 .9 2 2v16c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2zm0 2v16h14V4H5zm3 3h8v6H8V7zm0 8h3v2H8v-2zm5 0h3v2h-3v-2z'/> <path
d='M5 2h14c1.1 0 2 .9 2 2v16c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2zm0 2v16h14V4H5zm3 3h8v6H8V7zm0 8h3v2H8v-2zm5 0h3v2h-3v-2z' />
</svg> </svg>
</div> </div>
<div class='absolute top-4 right-4 animate-luxury-in' x-show='permissions[machine.id]'> <div class='absolute top-4 right-4 animate-luxury-in'
<div class='size-5 rounded-full bg-cyan-500 flex items-center justify-center shadow-lg shadow-cyan-500/30'> x-show='permissions[machine.id]'>
<svg class='size-3 text-white' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M5 13l4 4L19 7' /></svg> <div
class='size-5 rounded-full bg-cyan-500 flex items-center justify-center shadow-lg shadow-cyan-500/30'>
<svg class='size-3 text-white' fill='none' stroke='currentColor'
viewBox='0 0 24 24'>
<path stroke-linecap='round' stroke-linejoin='round' stroke-width='3'
d='M5 13l4 4L19 7' />
</svg>
</div> </div>
</div> </div>
</div> </div>
@@ -257,22 +340,32 @@
</div> </div>
</div> </div>
<div class='flex flex-col sm:flex-row justify-between items-center mt-10 pt-8 border-t border-slate-100 dark:border-slate-800 gap-6'> <div
class='flex flex-col sm:flex-row justify-between items-center mt-10 pt-8 border-t border-slate-100 dark:border-slate-800 gap-6'>
<div class='flex items-center gap-3'> <div class='flex items-center gap-3'>
<div class='flex -space-x-2'> <div class='flex -space-x-2'>
<template x-for='i in Math.min(3, Object.values(permissions).filter(v => v).length)' :key='i'> <template x-for='i in Math.min(3, Object.values(permissions).filter(v => v).length)'
<div class='size-6 rounded-full border-2 border-white dark:border-slate-900 bg-cyan-500 flex items-center justify-center'> :key='i'>
<svg class='size-3 text-white' fill='currentColor' viewBox='0 0 24 24'><path d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 14.5v-9l6 4.5-6 4.5z'/></svg> <div
class='size-6 rounded-full border-2 border-white dark:border-slate-900 bg-cyan-500 flex items-center justify-center'>
<svg class='size-3 text-white' fill='currentColor' viewBox='0 0 24 24'>
<path
d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 14.5v-9l6 4.5-6 4.5z' />
</svg>
</div> </div>
</template> </template>
</div> </div>
<p class='text-[10px] font-black text-slate-400 uppercase tracking-[0.2em]'> <p class='text-[10px] font-black text-slate-400 uppercase tracking-[0.2em]'>
{{ __('Selection') }}: <span class='text-cyan-500 text-xs' x-text='Object.values(permissions).filter(v => v).length'></span> / <span x-text='allMachines?.length || 0'></span> {{ __('Devices') }} {{ __('Selection') }}: <span class='text-cyan-500 text-xs'
x-text='Object.values(permissions).filter(v => v).length'></span> / <span
x-text='allMachines?.length || 0'></span> {{ __('Devices') }}
</p> </p>
</div> </div>
<div class='flex gap-4 w-full sm:w-auto'> <div class='flex gap-4 w-full sm:w-auto'>
<button @click='showPermissionModal = false' class='flex-1 sm:flex-none btn-luxury-ghost px-8'>{{ __('Cancel') }}</button> <button @click='showPermissionModal = false'
<button @click='savePermissions()' class='flex-1 sm:flex-none btn-luxury-primary px-12' :disabled='isPermissionsLoading'> class='flex-1 sm:flex-none btn-luxury-ghost px-8'>{{ __('Cancel') }}</button>
<button @click='savePermissions()' class='flex-1 sm:flex-none btn-luxury-primary px-12'
:disabled='isPermissionsLoading'>
<span>{{ __('Update Authorization') }}</span> <span>{{ __('Update Authorization') }}</span>
</button> </button>
</div> </div>

View File

@@ -74,7 +74,7 @@
<thead> <thead>
<tr class="bg-slate-50/50 dark:bg-slate-900/10"> <tr class="bg-slate-50/50 dark:bg-slate-900/10">
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Time') }}</th> <th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Time') }}</th>
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Machine') }}</th> <th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Machine Information') }}</th>
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Company') }}</th> <th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Company') }}</th>
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Category') }}</th> <th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Category') }}</th>
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Engineer') }}</th> <th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Engineer') }}</th>
@@ -89,8 +89,8 @@
</td> </td>
<td class="px-6 py-6 cursor-pointer group/cell" @click="openDetail({{ $record->load('machine', 'user', 'company')->toJson() }})"> <td class="px-6 py-6 cursor-pointer group/cell" @click="openDetail({{ $record->load('machine', 'user', 'company')->toJson() }})">
<div class="flex flex-col"> <div class="flex flex-col">
<span class="text-sm font-black text-slate-800 dark:text-slate-100 group-hover/cell:text-cyan-600 transition-colors">{{ $record->machine->name }}</span> <span class="text-sm font-black text-slate-800 dark:text-slate-100 group-hover/cell:text-cyan-600 transition-colors">{{ $record->machine->name ?? 'N/A' }}</span>
<span class="text-[10px] font-bold text-slate-400 uppercase tracking-widest group-hover/cell:text-cyan-500/60 transition-colors">{{ $record->machine->serial_no }}</span> <span class="text-[10px] font-bold text-slate-400 uppercase tracking-widest group-hover/cell:text-cyan-500/60 transition-colors">{{ $record->machine->serial_no ?? 'N/A' }}</span>
</div> </div>
</td> </td>
<td class="px-6 py-6"> <td class="px-6 py-6">

View File

@@ -192,7 +192,7 @@
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2 2xl:grid-cols-3 gap-8"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2 2xl:grid-cols-3 gap-8">
<div class="space-y-3"> <div class="space-y-3">
<label class="text-xs font-black text-emerald-500 uppercase tracking-widest pl-1">{{ __('Retail Price') }} <span class="text-rose-500">*</span></label> <label class="text-xs font-black text-emerald-500 uppercase tracking-widest pl-1">{{ __('Sale Price') }} <span class="text-rose-500">*</span></label>
<div class="flex items-center h-14 rounded-2xl border border-slate-100 dark:border-slate-800 bg-slate-50/50 dark:bg-slate-900/50 group focus-within:ring-2 focus-within:ring-emerald-500/20 transition-all overflow-hidden"> <div class="flex items-center h-14 rounded-2xl border border-slate-100 dark:border-slate-800 bg-slate-50/50 dark:bg-slate-900/50 group focus-within:ring-2 focus-within:ring-emerald-500/20 transition-all overflow-hidden">
<button type="button" @click="formData.price = Math.max(0, parseInt(formData.price || 0) - 1)" class="shrink-0 w-12 h-full flex items-center justify-center text-slate-400 hover:text-emerald-500 hover:bg-emerald-500/5 active:scale-90 transition-all"> <button type="button" @click="formData.price = Math.max(0, parseInt(formData.price || 0) - 1)" class="shrink-0 w-12 h-full flex items-center justify-center text-slate-400 hover:text-emerald-500 hover:bg-emerald-500/5 active:scale-90 transition-all">
<svg class="size-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="3"><path stroke-linecap="round" stroke-linejoin="round" d="M20 12H4"/></svg> <svg class="size-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="3"><path stroke-linecap="round" stroke-linejoin="round" d="M20 12H4"/></svg>

View File

@@ -207,7 +207,7 @@
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2 2xl:grid-cols-3 gap-8"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2 2xl:grid-cols-3 gap-8">
<div class="space-y-3"> <div class="space-y-3">
<label class="text-xs font-black text-emerald-500 uppercase tracking-widest pl-1">{{ __('Retail Price') }} <span class="text-rose-500">*</span></label> <label class="text-xs font-black text-emerald-500 uppercase tracking-widest pl-1">{{ __('Sale Price') }} <span class="text-rose-500">*</span></label>
<div class="flex items-center h-14 rounded-2xl border border-slate-100 dark:border-slate-800 bg-slate-50/50 dark:bg-slate-900/50 group focus-within:ring-2 focus-within:ring-emerald-500/20 transition-all overflow-hidden"> <div class="flex items-center h-14 rounded-2xl border border-slate-100 dark:border-slate-800 bg-slate-50/50 dark:bg-slate-900/50 group focus-within:ring-2 focus-within:ring-emerald-500/20 transition-all overflow-hidden">
<button type="button" @click="formData.price = Math.max(0, parseInt(formData.price || 0) - 1)" class="shrink-0 w-12 h-full flex items-center justify-center text-slate-400 hover:text-emerald-500 hover:bg-emerald-500/5 active:scale-90 transition-all"> <button type="button" @click="formData.price = Math.max(0, parseInt(formData.price || 0) - 1)" class="shrink-0 w-12 h-full flex items-center justify-center text-slate-400 hover:text-emerald-500 hover:bg-emerald-500/5 active:scale-90 transition-all">
<svg class="size-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="3"><path stroke-linecap="round" stroke-linejoin="round" d="M20 12H4"/></svg> <svg class="size-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="3"><path stroke-linecap="round" stroke-linejoin="round" d="M20 12H4"/></svg>

View File

@@ -71,7 +71,7 @@ $roleSelectConfig = [
@if(auth()->user()->isSystemAdmin()) @if(auth()->user()->isSystemAdmin())
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-center">{{ __('Company') }}</th> <th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-center">{{ __('Company') }}</th>
@endif @endif
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-center">{{ __('Price / Member') }}</th> <th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-center">{{ __('Sale Price') }}</th>
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-center">{{ __('Channel Limits (Track/Spring)') }}</th> <th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-center">{{ __('Channel Limits (Track/Spring)') }}</th>
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-center">{{ __('Status') }}</th> <th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-center">{{ __('Status') }}</th>
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-right">{{ __('Actions') }}</th> <th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-right">{{ __('Actions') }}</th>
@@ -305,7 +305,7 @@ $roleSelectConfig = [
<h3 class="text-xs font-black text-emerald-500 uppercase tracking-[0.3em]">{{ __('Pricing Information') }}</h3> <h3 class="text-xs font-black text-emerald-500 uppercase tracking-[0.3em]">{{ __('Pricing Information') }}</h3>
<div class="luxury-card divide-y divide-slate-50 dark:divide-white/5 overflow-hidden border border-slate-100 dark:border-white/5 shadow-sm"> <div class="luxury-card divide-y divide-slate-50 dark:divide-white/5 overflow-hidden border border-slate-100 dark:border-white/5 shadow-sm">
<div class="p-5 flex items-center justify-between group hover:bg-slate-50/50 dark:hover:bg-white/5 transition-colors"> <div class="p-5 flex items-center justify-between group hover:bg-slate-50/50 dark:hover:bg-white/5 transition-colors">
<span class="text-[15px] font-bold text-slate-500">{{ __('Retail Price') }}</span> <span class="text-[15px] font-bold text-slate-500">{{ __('Sale Price') }}</span>
<span class="text-lg font-black text-slate-800 dark:text-white">$<span x-text="formatNumber(selectedProduct?.price)"></span></span> <span class="text-lg font-black text-slate-800 dark:text-white">$<span x-text="formatNumber(selectedProduct?.price)"></span></span>
</div> </div>
<div class="p-5 flex items-center justify-between group hover:bg-slate-50/50 dark:hover:bg-white/5 transition-colors"> <div class="p-5 flex items-center justify-between group hover:bg-slate-50/50 dark:hover:bg-white/5 transition-colors">