[FEAT] 機台權限功能增強、UI 輕巧化與多語系優化
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 46s
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 46s
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
namespace App\Http\Controllers\Admin\Machine;
|
||||
|
||||
use App\Http\Controllers\Admin\AdminController;
|
||||
use App\Models\System\Company;
|
||||
use App\Models\Machine\Machine;
|
||||
use App\Models\System\User;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -19,6 +20,7 @@ class MachinePermissionController extends AdminController
|
||||
{
|
||||
$per_page = $request->input('per_page', 10);
|
||||
$search = $request->input('search');
|
||||
$company_id = $request->input('company_id');
|
||||
|
||||
$currentUser = auth()->user();
|
||||
|
||||
@@ -33,6 +35,9 @@ class MachinePermissionController extends AdminController
|
||||
// 非系統管理員僅能看到同公司的帳號 (因 User Model 排除 TenantScoped 全域過濾,需手動注入)
|
||||
if (!$currentUser->isSystemAdmin()) {
|
||||
$userQuery->where('company_id', $currentUser->company_id);
|
||||
} elseif ($company_id) {
|
||||
// 系統管理員的篩選邏輯
|
||||
$userQuery->where('company_id', $company_id);
|
||||
}
|
||||
|
||||
if ($search) {
|
||||
@@ -44,8 +49,9 @@ class MachinePermissionController extends AdminController
|
||||
}
|
||||
|
||||
$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'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,6 +22,7 @@ class MaintenanceController extends Controller
|
||||
$this->authorize('viewAny', MaintenanceRecord::class);
|
||||
|
||||
$query = MaintenanceRecord::with(['machine', 'user', 'company'])
|
||||
->whereHas('machine') // 確保僅顯示該帳號「看得見」的機台紀錄,避開因權限隔離導致的 null 報錯
|
||||
->latest('maintenance_at');
|
||||
|
||||
// 搜尋邏輯
|
||||
|
||||
31
lang/en.json
31
lang/en.json
@@ -73,10 +73,14 @@
|
||||
"Assign Machines": "Assign Machines",
|
||||
"Assigned Machines": "Assigned Machines",
|
||||
"Audit Management": "Audit Management",
|
||||
"Authorization updated successfully": "Authorization updated successfully",
|
||||
"Authorize": "Authorize",
|
||||
"Authorize Btn": "Authorize",
|
||||
"Authorized Accounts": "Authorized Accounts",
|
||||
"Authorized Accounts Tab": "Authorized Accounts",
|
||||
"Authorized Machines": "Authorized Machines",
|
||||
"Authorized Machines Management": "Authorized Machines Management",
|
||||
"Authorized Status": "Authorized",
|
||||
"Availability": "可用性 (Availability)",
|
||||
"Available Machines": "可供分配的機台",
|
||||
"Avatar updated successfully.": "Avatar updated successfully.",
|
||||
@@ -183,7 +187,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",
|
||||
@@ -324,7 +327,6 @@
|
||||
"Machine Model Settings": "Machine Model Settings",
|
||||
"Machine Name": "Machine Name",
|
||||
"Machine Permissions": "Machine Permissions",
|
||||
"Manage machine access permissions": "Manage machine access permissions",
|
||||
"Machine Registry": "Machine Registry",
|
||||
"Machine Reports": "Machine Reports",
|
||||
"Machine Restart": "Machine Restart",
|
||||
@@ -354,6 +356,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 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",
|
||||
@@ -572,6 +575,7 @@
|
||||
"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 company...",
|
||||
"Search customers...": "Search customers...",
|
||||
"Search machines by name or serial...": "Search machines by 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 name...": "Search serial or name...",
|
||||
"Search users...": "Search users...",
|
||||
"Select All": "全選",
|
||||
"Select All": "Select All",
|
||||
"Select Company": "Select Company Name",
|
||||
"Select Machine": "選擇機台",
|
||||
"Select Machine to view metrics": "請選擇機台以查看指標",
|
||||
"Select Machine": "Select Machine",
|
||||
"Select Machine to view metrics": "Please select a machine to view metrics",
|
||||
"Select Model": "Select Model",
|
||||
"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 date to sync data": "Select date to sync data",
|
||||
"Selected": "Selected",
|
||||
"Selected Date": "查詢日期",
|
||||
"Selected Date": "Search Date",
|
||||
"Selection": "Selection",
|
||||
"Serial & Version": "Serial & Version",
|
||||
"Serial NO": "Serial NO",
|
||||
"Deselect All": "Deselect All",
|
||||
"Serial NO": "SERIAL NO",
|
||||
"Serial No": "Serial No",
|
||||
"Serial Number": "Serial Number",
|
||||
"Show": "Show",
|
||||
@@ -652,6 +657,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.": "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.",
|
||||
"Time": "Time",
|
||||
"Time Slots": "Time Slots",
|
||||
@@ -676,6 +682,7 @@
|
||||
"Tutorial Page": "Tutorial Page",
|
||||
"Type": "Type",
|
||||
"UI Elements": "UI Elements",
|
||||
"Unauthorized Status": "Unauthorized",
|
||||
"Uncategorized": "Uncategorized",
|
||||
"Unified Operational Timeline": "Unified Operational Timeline",
|
||||
"Units": "Units",
|
||||
@@ -793,11 +800,5 @@
|
||||
"user": "一般用戶",
|
||||
"vs Yesterday": "vs Yesterday",
|
||||
"warehouses": "Warehouse Management",
|
||||
"待填寫": "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."
|
||||
"待填寫": "Pending"
|
||||
}
|
||||
67
lang/ja.json
67
lang/ja.json
@@ -74,7 +74,12 @@
|
||||
"Assigned Machines": "授權機台",
|
||||
"Audit Management": "監査管理",
|
||||
"Audit Permissions": "監査管理權限",
|
||||
"Authorization updated successfully": "認証が更新されました",
|
||||
"Authorize Btn": "認可",
|
||||
"Authorized Accounts Tab": "認定アカウント",
|
||||
"Authorized Machines": "授權機台",
|
||||
"Authorized Machines Management": "認定機台管理",
|
||||
"Authorized Status": "認可済み",
|
||||
"Availability": "可用性 (Availability)",
|
||||
"Available Machines": "可供分配的機台",
|
||||
"Avatar updated successfully.": "アバターが正常に更新されました。",
|
||||
@@ -163,7 +168,7 @@
|
||||
"Customer enabled successfully.": "顧客が正常に有効化されました。",
|
||||
"Customer updated successfully.": "顧客が正常に更新されました。",
|
||||
"Cycle Efficiency": "サイクル効率",
|
||||
"Daily Revenue": "日次収益",
|
||||
"Daily Revenue": "当日収益",
|
||||
"Danger Zone: Delete Account": "危険区域:アカウントの削除",
|
||||
"Dashboard": "ダッシュボード",
|
||||
"Data Configuration": "データ設定",
|
||||
@@ -179,7 +184,6 @@
|
||||
"Delete Product Confirmation": "商品削除の確認",
|
||||
"Deposit Bonus": "入金ボーナス",
|
||||
"Describe the repair or maintenance status...": "修理またはメンテナンスの状況を説明してください...",
|
||||
"Deselect All": "取消全選",
|
||||
"Detail": "詳細",
|
||||
"Device Information": "デバイス情報",
|
||||
"Device Status Logs": "デバイス状態ログ",
|
||||
@@ -242,7 +246,7 @@
|
||||
"Fill in the device repair or maintenance details": "デバイスの修理またはメンテナンスの詳細を入力してください",
|
||||
"Fill in the product details below": "以下に商品の詳細を入力してください",
|
||||
"Firmware Version": "ファームウェアバージョン",
|
||||
"Fleet Avg OEE": "フリート平均 OEE",
|
||||
"Fleet Avg OEE": "全機台平均OEE",
|
||||
"Fleet Performance": "全機隊效能",
|
||||
"From": "から",
|
||||
"From:": "開始:",
|
||||
@@ -297,7 +301,7 @@
|
||||
"Line Orders": "Line注文",
|
||||
"Line Permissions": "Line管理權限",
|
||||
"Line Products": "Line商品",
|
||||
"Live Fleet Updates": "ライブフリート更新",
|
||||
"Live Fleet Updates": "機台リアルタイム更新",
|
||||
"Loading machines...": "正在載入機台...",
|
||||
"Loading...": "読み込み中...",
|
||||
"Location": "場所",
|
||||
@@ -320,8 +324,7 @@
|
||||
"Machine Model Settings": "機台型號設定",
|
||||
"Machine Name": "機台名",
|
||||
"Machine Permissions": "機台権限",
|
||||
"Manage machine access permissions": "機台アクセス權限の管理",
|
||||
"Machine Registry": "機台登録",
|
||||
"Machine Registry": "機台登録簿",
|
||||
"Machine Reports": "機台レポート",
|
||||
"Machine Restart": "機台再起動",
|
||||
"Machine Settings": "機台設定",
|
||||
@@ -350,6 +353,7 @@
|
||||
"Manage Expiry": "進入效期管理",
|
||||
"Manage administrative and tenant accounts": "管理者およびテナントアカウントを管理します",
|
||||
"Manage all tenant accounts and validity": "すべてのテナントアカウントと有効期限を管理します",
|
||||
"Manage machine access permissions": "機台アクセス權限の管理",
|
||||
"Manage your catalog, prices, and multilingual details.": "カタログ、価格、多言語詳細を管理します。",
|
||||
"Manage your machine fleet and operational data": "機台フリートと運用データの管理",
|
||||
"Manage your profile information, security settings, and login history": "プロフィール情報、セキュリティ設定、ログイン履歴の管理",
|
||||
@@ -407,7 +411,7 @@
|
||||
"No machines available in this company.": "此客戶目前沒有可供分配的機台。",
|
||||
"No maintenance records found": "メンテナンス記録が見つかりません",
|
||||
"No matching logs found": "一致するログが見つかりません",
|
||||
"No matching machines": "一致する機台が見つかりません",
|
||||
"No matching machines": "一致する機台がありません",
|
||||
"No permissions": "権限項目なし",
|
||||
"No roles found.": "ロールが見つかりませんでした。",
|
||||
"No slots found": "未找到貨道資訊",
|
||||
@@ -418,8 +422,8 @@
|
||||
"Not Used Description": "不使用第三方支付介接",
|
||||
"Notes": "備考",
|
||||
"OEE": "OEE",
|
||||
"OEE Efficiency Trend": "OEE 効率トレンド",
|
||||
"OEE Score": "OEE スコア",
|
||||
"OEE Efficiency Trend": "OEE効率トレンド",
|
||||
"OEE Score": "OEE総合スコア",
|
||||
"OEE.Activity": "稼働アクティビティ",
|
||||
"OEE.Errors": "エラー",
|
||||
"OEE.Hours": "時間",
|
||||
@@ -432,12 +436,12 @@
|
||||
"Online": "オンライン",
|
||||
"Online Duration": "累積連線時數",
|
||||
"Online Machines": "オンライン機台",
|
||||
"Online Status": "オンライン状態",
|
||||
"Online Status": "オンラインステータス",
|
||||
"Only system roles can be assigned to platform administrative accounts.": "プラットフォーム管理アカウントにはシステムロールのみ割り当て可能です。",
|
||||
"Operational Parameters": "運用パラメータ",
|
||||
"Operations": "運用設定",
|
||||
"Optimal": "最適",
|
||||
"Optimized Performance": "最適化されたパフォーマンス",
|
||||
"Optimized Performance": "パフォーマンスの最適化",
|
||||
"Optimized for display. Supported formats: JPG, PNG, WebP.": "表示用に最適化されています。対応形式:JPG, PNG, WebP。",
|
||||
"Optional": "任意",
|
||||
"Order Management": "注文管理",
|
||||
@@ -447,7 +451,7 @@
|
||||
"Original:": "元:",
|
||||
"Other Permissions": "其他權限",
|
||||
"Others": "その他",
|
||||
"Output Count": "出力数",
|
||||
"Output Count": "出荷回数",
|
||||
"Owner": "会社名",
|
||||
"PARTNER_KEY": "パートナーキー",
|
||||
"PI_MERCHANT_ID": "Pi 拍錢包 加盟店ID",
|
||||
@@ -515,9 +519,9 @@
|
||||
"Quick search...": "クイック検索...",
|
||||
"Real-time OEE analysis awaits": "リアルタイム OEE 分析待機中",
|
||||
"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 performance analytics": "リアルタイム・パフォーマンス分析",
|
||||
"Real-time performance analytics": "リアルタイムパフォーマンス分析",
|
||||
"Real-time status monitoring": "リアルタイムステータス監視",
|
||||
"Receipt Printing": "レシート印刷",
|
||||
"Recent Login": "最近のログイン",
|
||||
@@ -572,6 +576,7 @@
|
||||
"Scale level and access control": "層級與存取控制",
|
||||
"Scan this code to quickly access the maintenance form for this device.": "このコードをスキャンして、このデバイスのメンテナンスフォームに素早くアクセスしてください。",
|
||||
"Search configurations...": "設定を検索...",
|
||||
"Search company...": "会社を検索...",
|
||||
"Search customers...": "顧客を検索...",
|
||||
"Search machines by name or serial...": "名称またはシリアル番号で検索...",
|
||||
"Search machines...": "マシン名またはシリアル番号で検索...",
|
||||
@@ -579,22 +584,23 @@
|
||||
"Search roles...": "ロールを検索...",
|
||||
"Search serial no or name...": "シリアル番号または名前を検索...",
|
||||
"Search serial or machine...": "シリアルまたはマシンを検索...",
|
||||
"Search serial or name...": "シリアル番号または名称で検索...",
|
||||
"Search serial or name...": "機台名またはシリアル番号で検索...",
|
||||
"Search users...": "ユーザーを検索...",
|
||||
"Select All": "全選",
|
||||
"Select All": "すべて選択",
|
||||
"Select Company": "会社名を選択",
|
||||
"Select Machine": "選擇機台",
|
||||
"Select Machine to view metrics": "請選擇機台以查看指標",
|
||||
"Select Machine": "機台を選択",
|
||||
"Select Machine to view metrics": "指標を表示する機台を選択してください",
|
||||
"Select Model": "型番を選択",
|
||||
"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": "データ同期の日付を選択してください",
|
||||
"Selected": "已選擇",
|
||||
"Selected Date": "查詢日期",
|
||||
"Selected": "選択済み",
|
||||
"Selected Date": "検索日",
|
||||
"Selection": "選択済み",
|
||||
"Deselect All": "すべて選択解除",
|
||||
"Serial & Version": "シリアルとバージョン",
|
||||
"Serial NO": "シリアル番号",
|
||||
"Serial NO": "機台シリアル番号",
|
||||
"Serial No": "機台シリアル番号",
|
||||
"Serial Number": "シリアル番号",
|
||||
"Show": "表示",
|
||||
@@ -654,6 +660,7 @@
|
||||
"The Super Admin role is immutable.": "スーパー管理者ロールは変更できません。",
|
||||
"The Super Admin role name cannot be modified.": "スーパー管理者のロール名は変更できません。",
|
||||
"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.": "このロールは他の会社に属しており、割り当てることはできません。",
|
||||
"Time": "時間",
|
||||
"Time Slots": "タイムスロット",
|
||||
@@ -665,7 +672,7 @@
|
||||
"Total Connected": "接続数合計",
|
||||
"Total Customers": "顧客總數",
|
||||
"Total Daily Sales": "本日累計銷量",
|
||||
"Total Gross Value": "総売上額",
|
||||
"Total Gross Value": "売上高計",
|
||||
"Total Logins": "總ログイン數",
|
||||
"Total Selected": "已選擇總數",
|
||||
"Total Slots": "合計スロット数",
|
||||
@@ -678,9 +685,10 @@
|
||||
"Tutorial Page": "チュートリアル画面",
|
||||
"Type": "タイプ",
|
||||
"UI Elements": "UI要素",
|
||||
"Unauthorized Status": "未認可",
|
||||
"Uncategorized": "未分類",
|
||||
"Unified Operational Timeline": "整合式營運時序圖",
|
||||
"Units": "ユニット",
|
||||
"Units": "台",
|
||||
"Unknown": "不明",
|
||||
"Update": "更新",
|
||||
"Update Authorization": "権限を更新",
|
||||
@@ -698,7 +706,7 @@
|
||||
"Utilization Rate": "稼働率",
|
||||
"Utilization Timeline": "稼動時序",
|
||||
"Utilization, OEE and Operational Intelligence": "稼動率、OEE と運用インテリジェンス",
|
||||
"Utilized Time": "稼働時間",
|
||||
"Utilized Time": "稼動持続時間",
|
||||
"Valid Until": "有効期限",
|
||||
"Validation Error": "検証エラー",
|
||||
"Vending Page": "販売画面",
|
||||
@@ -795,12 +803,5 @@
|
||||
"user": "一般用戶",
|
||||
"vs Yesterday": "前日比",
|
||||
"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.": "これはシステム管理者ロールです。システムの安定性を確保するため、名称は固定されています。"
|
||||
"待填寫": "待填寫"
|
||||
}
|
||||
@@ -77,10 +77,14 @@
|
||||
"Assigned Machines": "授權機台",
|
||||
"Audit Management": "稽核管理",
|
||||
"Audit Permissions": "稽核管理權限",
|
||||
"Authorization updated successfully": "授權更新成功",
|
||||
"Authorize": "授權",
|
||||
"Authorize Btn": "授權",
|
||||
"Authorized Accounts": "授權帳號",
|
||||
"Authorized Accounts Tab": "授權帳號",
|
||||
"Authorized Machines": "授權機台",
|
||||
"Authorized Machines Management": "授權機台管理",
|
||||
"Authorized Status": "已授權",
|
||||
"Availability": "可用性 (Availability)",
|
||||
"Available Machines": "可供分配的機台",
|
||||
"Avatar updated successfully.": "頭像已成功更新。",
|
||||
@@ -189,7 +193,6 @@
|
||||
"Delete Product Confirmation": "刪除商品確認",
|
||||
"Deposit Bonus": "儲值回饋",
|
||||
"Describe the repair or maintenance status...": "請描述維修或保養狀況...",
|
||||
"Deselect All": "取消全選",
|
||||
"Detail": "詳細",
|
||||
"Device Information": "設備資訊",
|
||||
"Device Status Logs": "設備狀態紀錄",
|
||||
@@ -322,7 +325,7 @@
|
||||
"Machine Details": "機台詳情",
|
||||
"Machine Images": "機台照片",
|
||||
"Machine Info": "機台資訊",
|
||||
"Machine Information": "機台資訊",
|
||||
"Machine Information": "機器資訊",
|
||||
"Machine List": "機台列表",
|
||||
"Machine Login Logs": "機台登入紀錄",
|
||||
"Machine Logs": "機台日誌",
|
||||
@@ -332,7 +335,6 @@
|
||||
"Machine Model Settings": "機台型號設定",
|
||||
"Machine Name": "機台名稱",
|
||||
"Machine Permissions": "機台權限",
|
||||
"Manage machine access permissions": "管理機台存取權限",
|
||||
"Machine Registry": "機台清冊",
|
||||
"Machine Reports": "機台報表",
|
||||
"Machine Restart": "機台重啟",
|
||||
@@ -362,6 +364,7 @@
|
||||
"Manage Expiry": "進入效期管理",
|
||||
"Manage administrative and tenant accounts": "管理系統管理者與租戶帳號",
|
||||
"Manage all tenant accounts and validity": "管理所有租戶帳號與合約效期",
|
||||
"Manage machine access permissions": "管理機台存取權限",
|
||||
"Manage your catalog, prices, and multilingual details.": "管理您的商品型錄、價格及多語系詳情。",
|
||||
"Manage your machine fleet and operational data": "管理您的機台群組與營運數據",
|
||||
"Manage your profile information, security settings, and login history": "管理您的個人資訊、安全設定與登入紀錄",
|
||||
@@ -421,7 +424,7 @@
|
||||
"No machines available in this company.": "此客戶目前沒有可供分配的機台。",
|
||||
"No maintenance records found": "找不到維修紀錄",
|
||||
"No matching logs found": "找不到符合條件的日誌",
|
||||
"No matching machines": "找不到符合的機台",
|
||||
"No matching machines": "查無匹配機台",
|
||||
"No permissions": "無權限項目",
|
||||
"No roles found.": "找不到角色資料。",
|
||||
"No slots found": "未找到貨道資訊",
|
||||
@@ -432,7 +435,7 @@
|
||||
"Not Used Description": "不使用第三方支付介接",
|
||||
"Notes": "備註",
|
||||
"OEE Efficiency Trend": "OEE 效率趨勢",
|
||||
"OEE Score": "OEE 綜合得分",
|
||||
"OEE Score": "OEE 綜合評分",
|
||||
"OEE.Activity": "營運活動",
|
||||
"OEE.Errors": "異常",
|
||||
"OEE.Hours": "小時",
|
||||
@@ -450,7 +453,7 @@
|
||||
"Operational Parameters": "運作參數",
|
||||
"Operations": "運作設定",
|
||||
"Optimal": "良好",
|
||||
"Optimized Performance": "效能優化",
|
||||
"Optimized Performance": "效能最佳化",
|
||||
"Optimized for display. Supported formats: JPG, PNG, WebP.": "已針對顯示進行優化。支援格式:JPG, PNG, WebP。",
|
||||
"Optional": "選填",
|
||||
"Order Management": "訂單管理",
|
||||
@@ -460,7 +463,7 @@
|
||||
"Original:": "原:",
|
||||
"Other Permissions": "其他權限",
|
||||
"Others": "其他功能",
|
||||
"Output Count": "出貨數量",
|
||||
"Output Count": "出貨次數",
|
||||
"Owner": "公司名稱",
|
||||
"PARTNER_KEY": "PARTNER_KEY",
|
||||
"PI_MERCHANT_ID": "Pi 拍錢包 商店代號",
|
||||
@@ -589,6 +592,7 @@
|
||||
"Scale level and access control": "層級與存取控制",
|
||||
"Scan this code to quickly access the maintenance form for this device.": "掃描此 QR Code 即可快速進入此設備的維修單填寫頁面。",
|
||||
"Search accounts...": "搜尋帳號...",
|
||||
"Search company...": "搜尋公司...",
|
||||
"Search configurations...": "搜尋設定...",
|
||||
"Search customers...": "搜尋客戶...",
|
||||
"Search machines by name or serial...": "搜尋機台名稱或序號...",
|
||||
@@ -598,6 +602,7 @@
|
||||
"Search roles...": "搜尋角色...",
|
||||
"Search serial no or name...": "搜尋序號或機台名稱...",
|
||||
"Search serial or machine...": "搜尋序號或機台名稱...",
|
||||
"Search serial or name...": "搜尋序號或機台名稱...",
|
||||
"Search users...": "搜尋用戶...",
|
||||
"Select All": "全選",
|
||||
"Select Category": "選擇類別",
|
||||
@@ -607,11 +612,14 @@
|
||||
"Select Model": "選擇型號",
|
||||
"Select Owner": "選擇公司名稱",
|
||||
"Select a machine to deep dive": "請選擇機台以開始深度分析",
|
||||
"Select an asset from the left to start analysis": "選擇左側機台以開始分析數據",
|
||||
"Select date to sync data": "選擇日期以同步數據",
|
||||
"Selected": "已選擇",
|
||||
"Selected Date": "查詢日期",
|
||||
"Selection": "已選擇",
|
||||
"Serial & Version": "序號與版本",
|
||||
"Deselect All": "取消全選",
|
||||
"Serial NO": "機台序號",
|
||||
"Serial No": "機台序號",
|
||||
"Serial Number": "機台序號",
|
||||
"Show": "顯示",
|
||||
@@ -674,6 +682,7 @@
|
||||
"The Super Admin role is immutable.": "超級管理員角色不可修改。",
|
||||
"The Super Admin role name cannot be modified.": "超級管理員角色的名稱無法修改。",
|
||||
"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.": "此角色屬於其他公司,無法指派。",
|
||||
"Time": "時間",
|
||||
"Time Slots": "時段組合",
|
||||
@@ -686,7 +695,7 @@
|
||||
"Total Connected": "總計連線數",
|
||||
"Total Customers": "客戶總數",
|
||||
"Total Daily Sales": "本日累計銷量",
|
||||
"Total Gross Value": "銷售總結",
|
||||
"Total Gross Value": "銷售總額",
|
||||
"Total Logins": "總登入次數",
|
||||
"Total Selected": "已選擇總數",
|
||||
"Total Slots": "總貨道數",
|
||||
@@ -700,6 +709,7 @@
|
||||
"Tutorial Page": "教學頁",
|
||||
"Type": "類型",
|
||||
"UI Elements": "UI元素",
|
||||
"Unauthorized Status": "未授權",
|
||||
"Uncategorized": "未分類",
|
||||
"Unified Operational Timeline": "整合式營運時序圖",
|
||||
"Units": "台",
|
||||
@@ -818,11 +828,5 @@
|
||||
"user": "一般用戶",
|
||||
"vs Yesterday": "較昨日",
|
||||
"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.": "這是系統管理員角色,名稱已鎖定以確保系統穩定性。"
|
||||
"待填寫": "待填寫"
|
||||
}
|
||||
@@ -42,6 +42,16 @@
|
||||
togglePermission(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() {
|
||||
const machineIds = Object.keys(this.permissions).filter(id => this.permissions[id]);
|
||||
|
||||
@@ -80,19 +90,29 @@
|
||||
<!-- 2. Main Content Card -->
|
||||
<div class="luxury-card rounded-3xl p-8 animate-luxury-in">
|
||||
<!-- Toolbar & Filters -->
|
||||
<div class="flex items-center justify-between mb-8">
|
||||
<form method="GET" action="{{ route('admin.machines.permissions') }}" class="relative group">
|
||||
<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="flex flex-wrap items-center gap-4 w-full md:w-auto">
|
||||
<div class="relative group">
|
||||
<span class="absolute inset-y-0 left-0 flex items-center pl-4 pointer-events-none z-10">
|
||||
<svg class="h-4 w-4 text-slate-400 group-focus-within:text-cyan-500 transition-colors"
|
||||
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="11" cy="11" r="8"></circle>
|
||||
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
||||
</svg>
|
||||
</span>
|
||||
<input type="text" name="search" value="{{ request('search') }}"
|
||||
placeholder="{{ __('Search accounts...') }}"
|
||||
class="luxury-input py-2.5 pl-12 pr-6 block w-64">
|
||||
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>
|
||||
</div>
|
||||
|
||||
@@ -100,13 +120,17 @@
|
||||
<table class="w-full text-left border-separate border-spacing-y-0">
|
||||
<thead>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -115,40 +139,57 @@
|
||||
<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">
|
||||
<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">
|
||||
<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>
|
||||
</div>
|
||||
<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 class="text-xs font-mono font-bold text-slate-500 tracking-widest uppercase">{{ $user->username }}</span>
|
||||
<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>
|
||||
</td>
|
||||
<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') }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-6">
|
||||
<div class="flex flex-wrap gap-2 justify-center lg:justify-start max-w-[400px] mx-auto lg:mx-0">
|
||||
<td class="px-6 py-4">
|
||||
<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)
|
||||
<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">
|
||||
<span class="text-xs font-black text-slate-700 dark:text-slate-200 leading-tight">{{ $m->name }}</span>
|
||||
<span class="text-[10px] font-mono font-bold text-cyan-500 tracking-tighter mt-1">{{ $m->serial_no }}</span>
|
||||
<div
|
||||
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-[11px] font-black text-slate-700 dark:text-slate-200 leading-tight">{{
|
||||
$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
|
||||
<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
|
||||
class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest opacity-40 italic">--
|
||||
{{ __('None') }} --</span>
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-6 text-right">
|
||||
<button @click="openPermissionModal({{ json_encode(['id' => $user->id, 'name' => $user->name]) }})"
|
||||
<button
|
||||
@click="openPermissionModal({{ json_encode(['id' => $user->id, 'name' => $user->name]) }})"
|
||||
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>
|
||||
<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>
|
||||
</button>
|
||||
</td>
|
||||
@@ -157,8 +198,12 @@
|
||||
<tr>
|
||||
<td colspan="4" class="px-6 py-24 text-center">
|
||||
<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>
|
||||
<p class="text-slate-400 font-extrabold tracking-widest uppercase text-xs">{{ __('No accounts found') }}</p>
|
||||
<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>
|
||||
<p class="text-slate-400 font-extrabold tracking-widest uppercase text-xs">{{ __('No
|
||||
accounts found') }}</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -183,8 +228,7 @@
|
||||
|
||||
<span class='hidden sm:inline-block sm:align-middle sm:h-screen'>​</span>
|
||||
|
||||
<div x-show='showPermissionModal'
|
||||
x-transition:enter='ease-out duration-300'
|
||||
<div x-show='showPermissionModal' 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-end='opacity-100 translate-y-0 sm:scale-100'
|
||||
x-transition:leave='ease-in duration-200'
|
||||
@@ -194,62 +238,101 @@
|
||||
|
||||
<div class='flex justify-between items-center mb-8'>
|
||||
<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'>
|
||||
<span class='text-[10px] font-black text-slate-400 uppercase tracking-[0.2em]'>{{ __('Account') }}:</span>
|
||||
<span class='text-xs font-bold text-cyan-500 uppercase tracking-widest' x-text='targetUserName'></span>
|
||||
<span class='text-[10px] font-black text-slate-400 uppercase tracking-[0.2em]'>{{
|
||||
__('Account') }}:</span>
|
||||
<span class='text-xs font-bold text-cyan-500 uppercase tracking-widest'
|
||||
x-text='targetUserName'></span>
|
||||
</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'>
|
||||
<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 @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'>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class='relative min-h-[400px]'>
|
||||
<div class='mb-6'>
|
||||
<div class='relative group'>
|
||||
<div class='mb-6 flex flex-col md:flex-row gap-4 items-center'>
|
||||
<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'>
|
||||
<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>
|
||||
<line x1='21' y1='21' x2='16.65' y2='16.65'></line>
|
||||
</svg>
|
||||
</span>
|
||||
<input type='text' x-model='permissionSearchQuery' placeholder='{{ __("Search machines...") }}'
|
||||
class='luxury-input py-3 pl-12 pr-6 block w-full text-sm' @click.stop>
|
||||
<input type='text' x-model='permissionSearchQuery'
|
||||
placeholder='{{ __("Search machines...") }}'
|
||||
class='luxury-input py-3 pl-12 pr-6 block w-full text-sm font-bold' @click.stop>
|
||||
</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>
|
||||
|
||||
<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='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
|
||||
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>
|
||||
</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'>
|
||||
<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
|
||||
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)'
|
||||
: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'>
|
||||
<div class='flex flex-col relative z-10'>
|
||||
<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>
|
||||
<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"'
|
||||
<div class='size-2 rounded-full'
|
||||
: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>
|
||||
</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>
|
||||
</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'>
|
||||
<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>
|
||||
</div>
|
||||
<div class='absolute top-4 right-4 animate-luxury-in' x-show='permissions[machine.id]'>
|
||||
<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 class='absolute top-4 right-4 animate-luxury-in'
|
||||
x-show='permissions[machine.id]'>
|
||||
<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>
|
||||
@@ -257,22 +340,32 @@
|
||||
</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 -space-x-2'>
|
||||
<template x-for='i in Math.min(3, Object.values(permissions).filter(v => v).length)' :key='i'>
|
||||
<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>
|
||||
<template x-for='i in Math.min(3, Object.values(permissions).filter(v => v).length)'
|
||||
:key='i'>
|
||||
<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>
|
||||
</template>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
<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='savePermissions()' class='flex-1 sm:flex-none btn-luxury-primary px-12' :disabled='isPermissionsLoading'>
|
||||
<button @click='showPermissionModal = false'
|
||||
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>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
<thead>
|
||||
<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">{{ __('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">{{ __('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>
|
||||
@@ -89,8 +89,8 @@
|
||||
</td>
|
||||
<td class="px-6 py-6 cursor-pointer group/cell" @click="openDetail({{ $record->load('machine', 'user', 'company')->toJson() }})">
|
||||
<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-[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-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 ?? 'N/A' }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-6">
|
||||
|
||||
@@ -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="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">
|
||||
<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>
|
||||
|
||||
@@ -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="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">
|
||||
<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>
|
||||
|
||||
@@ -71,7 +71,7 @@ $roleSelectConfig = [
|
||||
@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>
|
||||
@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">{{ __('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>
|
||||
@@ -305,7 +305,7 @@ $roleSelectConfig = [
|
||||
<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="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>
|
||||
</div>
|
||||
<div class="p-5 flex items-center justify-between group hover:bg-slate-50/50 dark:hover:bg-white/5 transition-colors">
|
||||
|
||||
Reference in New Issue
Block a user