[REFACTOR] 簡化權限管理介面,整合權限設定至角色管理,並完成多語系支援
This commit is contained in:
@@ -177,7 +177,36 @@ description: 定義 Star Cloud 管理後台的「極簡奢華風」設計規範
|
|||||||
- **指示文字**:
|
- **指示文字**:
|
||||||
- 行動端隱藏多餘詞彙,僅保留「1 - 10 / 50」格式。
|
- 行動端隱藏多餘詞彙,僅保留「1 - 10 / 50」格式。
|
||||||
- 數字顏色對齊 `text-slate-600` (深色: `text-slate-300`)。
|
- 數字顏色對齊 `text-slate-600` (深色: `text-slate-300`)。
|
||||||
```
|
## 9. 系統兼容性與標準化 (Compatibility & Standardization)
|
||||||
|
|
||||||
|
為了確保在不同版本的開發環境中(如目前專案使用的 Tailwind CSS v3.1)UI 都能正確呈現,並維持全站操作感一致,必須遵守以下額外規範。
|
||||||
|
|
||||||
|
### Tailwind CSS 版本兼容性 (v3.1)
|
||||||
|
- **禁止使用 `size-` 屬性**: 舊版不支援 `size-4` 等語法,請一律分拆寫作 `w-4 h-4`。
|
||||||
|
- **避免非標準間距**: 避免使用 `4.5` (`18px`) 等任意值,優先使用標準等級如 `4` (`16px`) 或 `5` (`20px`)。
|
||||||
|
|
||||||
|
### 標準操作按鈕 (Standard Action Icons)
|
||||||
|
表格內的操作欄位(如「編輯」、「刪除」)必須使用以下定義之標準:
|
||||||
|
|
||||||
|
- **共同樣式**:
|
||||||
|
- 容器: `p-2 rounded-lg bg-slate-50 dark:bg-slate-800`
|
||||||
|
- 主色: `text-slate-400`
|
||||||
|
- 圖示粗細: `stroke-width="2.5"`
|
||||||
|
- 尺寸: `w-4 h-4`
|
||||||
|
|
||||||
|
- **編輯按鈕 (Edit)**:
|
||||||
|
- 懸停特效: `hover:text-cyan-500 hover:bg-cyan-500/10 hover:border-cyan-500/20`
|
||||||
|
- SVG 路徑:
|
||||||
|
```html
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10"/></svg>
|
||||||
|
```
|
||||||
|
|
||||||
|
- **刪除按鈕 (Delete)**:
|
||||||
|
- 懸停特效: `hover:text-rose-500 hover:bg-rose-500/10 hover:border-rose-500/20`
|
||||||
|
- SVG 路徑:
|
||||||
|
```html
|
||||||
|
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/><line x1="10" x2="10" y1="11" y2="17"/><line x1="14" x2="14" y1="11" y2="17"/></svg>
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ class CompanyController extends Controller
|
|||||||
$query->where('status', $request->status);
|
$query->where('status', $request->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
$limit = $request->input('limit', 10);
|
$per_page = $request->input('per_page', 10);
|
||||||
$companies = $query->latest()->paginate($limit)->withQueryString();
|
$companies = $query->latest()->paginate($per_page)->withQueryString();
|
||||||
|
|
||||||
return view('admin.companies.index', compact('companies'));
|
return view('admin.companies.index', compact('companies'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,9 @@ class DashboardController extends Controller
|
|||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
// 每頁顯示筆數限制 (預設為 10)
|
// 每頁顯示筆數限制 (預設為 10)
|
||||||
$perPage = $request->get('limit', 10);
|
$perPage = (int) request()->input('per_page', 10);
|
||||||
|
if ($perPage <= 0) $perPage = 10;
|
||||||
|
|
||||||
// 從資料庫獲取真實統計數據
|
// 從資料庫獲取真實統計數據
|
||||||
$totalRevenue = \App\Models\Member\MemberWallet::sum('balance');
|
$totalRevenue = \App\Models\Member\MemberWallet::sum('balance');
|
||||||
$activeMachines = Machine::where('status', 'online')->count();
|
$activeMachines = Machine::where('status', 'online')->count();
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class DataConfigController extends Controller
|
|||||||
public function adminProducts()
|
public function adminProducts()
|
||||||
{
|
{
|
||||||
return view('admin.placeholder', [
|
return view('admin.placeholder', [
|
||||||
'title' => '管理者可賣商品',
|
'title' => '商品狀態',
|
||||||
'description' => '管理者商品銷售權限',
|
'description' => '管理者商品銷售權限',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ class MachineController extends AdminController
|
|||||||
*/
|
*/
|
||||||
public function index(Request $request): View
|
public function index(Request $request): View
|
||||||
{
|
{
|
||||||
$limit = $request->input('limit', 10);
|
$per_page = $request->input('per_page', 10);
|
||||||
$machines = Machine::query()
|
$machines = Machine::query()
|
||||||
->when($request->status, function ($query, $status) {
|
->when($request->status, function ($query, $status) {
|
||||||
return $query->where('status', $status);
|
return $query->where('status', $status);
|
||||||
})
|
})
|
||||||
->latest()
|
->latest()
|
||||||
->paginate($limit)
|
->paginate($per_page)
|
||||||
->withQueryString();
|
->withQueryString();
|
||||||
|
|
||||||
return view('admin.machines.index', compact('machines'));
|
return view('admin.machines.index', compact('machines'));
|
||||||
@@ -42,7 +42,7 @@ class MachineController extends AdminController
|
|||||||
*/
|
*/
|
||||||
public function logs(Request $request): View
|
public function logs(Request $request): View
|
||||||
{
|
{
|
||||||
$limit = $request->input('limit', 20);
|
$per_page = $request->input('per_page', 20);
|
||||||
$logs = \App\Models\Machine\MachineLog::with('machine')
|
$logs = \App\Models\Machine\MachineLog::with('machine')
|
||||||
->when($request->level, function ($query, $level) {
|
->when($request->level, function ($query, $level) {
|
||||||
return $query->where('level', $level);
|
return $query->where('level', $level);
|
||||||
@@ -51,7 +51,7 @@ class MachineController extends AdminController
|
|||||||
return $query->where('machine_id', $machineId);
|
return $query->where('machine_id', $machineId);
|
||||||
})
|
})
|
||||||
->latest()
|
->latest()
|
||||||
->paginate($limit)->withQueryString();
|
->paginate($per_page)->withQueryString();
|
||||||
|
|
||||||
$machines = Machine::select('id', 'name')->get();
|
$machines = Machine::select('id', 'name')->get();
|
||||||
|
|
||||||
|
|||||||
@@ -7,93 +7,19 @@ use Illuminate\Http\Request;
|
|||||||
|
|
||||||
class PermissionController extends Controller
|
class PermissionController extends Controller
|
||||||
{
|
{
|
||||||
// APP功能管理
|
|
||||||
public function appFeatures()
|
|
||||||
{
|
|
||||||
return view('admin.placeholder', [
|
|
||||||
'title' => 'APP功能管理',
|
|
||||||
'description' => 'APP功能權限設定',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 資料設定權限
|
|
||||||
public function dataConfig()
|
|
||||||
{
|
|
||||||
return view('admin.placeholder', [
|
|
||||||
'title' => '資料設定權限',
|
|
||||||
'description' => '資料設定功能權限',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 銷售管理權限
|
|
||||||
public function sales()
|
|
||||||
{
|
|
||||||
return view('admin.placeholder', [
|
|
||||||
'title' => '銷售管理權限',
|
|
||||||
'description' => '銷售管理功能權限',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 機台管理權限
|
|
||||||
public function machines()
|
|
||||||
{
|
|
||||||
return view('admin.placeholder', [
|
|
||||||
'title' => '機台管理權限',
|
|
||||||
'description' => '機台管理功能權限',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 倉庫管理權限
|
|
||||||
public function warehouses()
|
|
||||||
{
|
|
||||||
return view('admin.placeholder', [
|
|
||||||
'title' => '倉庫管理權限',
|
|
||||||
'description' => '倉庫管理功能權限',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分析管理權限
|
|
||||||
public function analysis()
|
|
||||||
{
|
|
||||||
return view('admin.placeholder', [
|
|
||||||
'title' => '分析管理權限',
|
|
||||||
'description' => '分析管理功能權限',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 稽核管理權限
|
|
||||||
public function audit()
|
|
||||||
{
|
|
||||||
return view('admin.placeholder', [
|
|
||||||
'title' => '稽核管理權限',
|
|
||||||
'description' => '稽核管理功能權限',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 遠端管理權限
|
|
||||||
public function remote()
|
|
||||||
{
|
|
||||||
return view('admin.placeholder', [
|
|
||||||
'title' => '遠端管理權限',
|
|
||||||
'description' => '遠端管理功能權限',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Line管理權限
|
|
||||||
public function line()
|
|
||||||
{
|
|
||||||
return view('admin.placeholder', [
|
|
||||||
'title' => 'Line管理權限',
|
|
||||||
'description' => 'Line管理功能權限',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 權限角色設定
|
// 權限角色設定
|
||||||
public function roles()
|
public function roles()
|
||||||
{
|
{
|
||||||
$limit = request()->input('limit', 10);
|
$per_page = request()->input('per_page', 10);
|
||||||
$roles = \Spatie\Permission\Models\Role::withCount('users')->latest()->paginate($limit)->withQueryString();
|
$roles = \Spatie\Permission\Models\Role::with(['permissions', 'users'])->latest()->paginate($per_page)->withQueryString();
|
||||||
return view('admin.permission.roles', compact('roles'));
|
$all_permissions = \Spatie\Permission\Models\Permission::all()->groupBy(function($perm) {
|
||||||
|
if (str_starts_with($perm->name, 'menu.')) {
|
||||||
|
return 'menu';
|
||||||
|
}
|
||||||
|
return 'other';
|
||||||
|
});
|
||||||
|
|
||||||
|
return view('admin.permission.roles', compact('roles', 'all_permissions'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -103,14 +29,20 @@ class PermissionController extends Controller
|
|||||||
{
|
{
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'name' => 'required|string|max:255|unique:roles,name',
|
'name' => 'required|string|max:255|unique:roles,name',
|
||||||
|
'permissions' => 'nullable|array',
|
||||||
|
'permissions.*' => 'string|exists:permissions,name',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
\Spatie\Permission\Models\Role::create([
|
$role = \Spatie\Permission\Models\Role::create([
|
||||||
'name' => $validated['name'],
|
'name' => $validated['name'],
|
||||||
'guard_name' => 'web',
|
'guard_name' => 'web',
|
||||||
'is_system' => false,
|
'is_system' => false,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if (!empty($validated['permissions'])) {
|
||||||
|
$role->syncPermissions($validated['permissions']);
|
||||||
|
}
|
||||||
|
|
||||||
return redirect()->back()->with('success', __('Role created successfully.'));
|
return redirect()->back()->with('success', __('Role created successfully.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,15 +53,17 @@ class PermissionController extends Controller
|
|||||||
{
|
{
|
||||||
$role = \Spatie\Permission\Models\Role::findOrFail($id);
|
$role = \Spatie\Permission\Models\Role::findOrFail($id);
|
||||||
|
|
||||||
if ($role->is_system) {
|
|
||||||
return redirect()->back()->with('error', __('System roles cannot be renamed.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'name' => 'required|string|max:255|unique:roles,name,' . $id,
|
'name' => 'required|string|max:255|unique:roles,name,' . $id,
|
||||||
|
'permissions' => 'nullable|array',
|
||||||
|
'permissions.*' => 'string|exists:permissions,name',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$role->update(['name' => $validated['name']]);
|
if (!$role->is_system) {
|
||||||
|
$role->update(['name' => $validated['name']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$role->syncPermissions($validated['permissions'] ?? []);
|
||||||
|
|
||||||
return redirect()->back()->with('success', __('Role updated successfully.'));
|
return redirect()->back()->with('success', __('Role updated successfully.'));
|
||||||
}
|
}
|
||||||
@@ -154,15 +88,6 @@ class PermissionController extends Controller
|
|||||||
return redirect()->back()->with('success', __('Role deleted successfully.'));
|
return redirect()->back()->with('success', __('Role deleted successfully.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 其他功能管理
|
|
||||||
public function others()
|
|
||||||
{
|
|
||||||
return view('admin.placeholder', [
|
|
||||||
'title' => '其他功能管理',
|
|
||||||
'description' => '其他特殊功能權限',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 帳號管理
|
// 帳號管理
|
||||||
public function accounts(Request $request)
|
public function accounts(Request $request)
|
||||||
{
|
{
|
||||||
@@ -187,11 +112,12 @@ class PermissionController extends Controller
|
|||||||
$query->where('company_id', $request->company_id);
|
$query->where('company_id', $request->company_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$limit = $request->input('limit', 10);
|
$per_page = $request->input('per_page', 10);
|
||||||
$users = $query->latest()->paginate($limit)->withQueryString();
|
$users = $query->latest()->paginate($per_page)->withQueryString();
|
||||||
$companies = auth()->user()->isSystemAdmin() ? \App\Models\System\Company::all() : collect();
|
$companies = auth()->user()->isSystemAdmin() ? \App\Models\System\Company::all() : collect();
|
||||||
|
$roles = \Spatie\Permission\Models\Role::all();
|
||||||
|
|
||||||
return view('admin.data-config.accounts', compact('users', 'companies'));
|
return view('admin.data-config.accounts', compact('users', 'companies', 'roles'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -281,13 +207,4 @@ class PermissionController extends Controller
|
|||||||
|
|
||||||
return redirect()->back()->with('success', __('Account deleted successfully.'));
|
return redirect()->back()->with('success', __('Account deleted successfully.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// AI智能預測
|
|
||||||
public function aiPrediction()
|
|
||||||
{
|
|
||||||
return view('admin.placeholder', [
|
|
||||||
'title' => 'AI智能預測',
|
|
||||||
'description' => 'AI功能權限設定',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,35 @@ class RoleSeeder extends Seeder
|
|||||||
// 重設快取
|
// 重設快取
|
||||||
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
|
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
|
||||||
|
|
||||||
|
// 建立權限
|
||||||
|
$permissions = [
|
||||||
|
'menu.members',
|
||||||
|
'menu.machines',
|
||||||
|
'menu.app',
|
||||||
|
'menu.warehouses',
|
||||||
|
'menu.sales',
|
||||||
|
'menu.analysis',
|
||||||
|
'menu.audit',
|
||||||
|
'menu.data-config',
|
||||||
|
'menu.remote',
|
||||||
|
'menu.line',
|
||||||
|
'menu.reservation',
|
||||||
|
'menu.special-permission',
|
||||||
|
'menu.companies',
|
||||||
|
'menu.accounts',
|
||||||
|
'menu.roles',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($permissions as $permission) {
|
||||||
|
Permission::updateOrCreate(['name' => $permission, 'guard_name' => 'web']);
|
||||||
|
}
|
||||||
|
|
||||||
// 建立角色
|
// 建立角色
|
||||||
Role::updateOrCreate(
|
$superAdmin = Role::updateOrCreate(
|
||||||
['name' => 'super-admin'],
|
['name' => 'super-admin'],
|
||||||
['is_system' => true]
|
['is_system' => true]
|
||||||
);
|
);
|
||||||
|
$superAdmin->syncPermissions(Permission::all());
|
||||||
|
|
||||||
Role::updateOrCreate(
|
Role::updateOrCreate(
|
||||||
['name' => 'tenant-admin'],
|
['name' => 'tenant-admin'],
|
||||||
|
|||||||
39
lang/en.json
39
lang/en.json
@@ -148,22 +148,37 @@
|
|||||||
"AI Prediction": "AI Prediction",
|
"AI Prediction": "AI Prediction",
|
||||||
"Roles": "Roles",
|
"Roles": "Roles",
|
||||||
"Role Management": "Role Management",
|
"Role Management": "Role Management",
|
||||||
"Define and manage security roles for the system.": "Define and manage security roles for the system.",
|
"Define and manage security roles and permissions.": "Define and manage security roles and permissions.",
|
||||||
"Add Role": "Add Role",
|
"Search roles...": "Search roles...",
|
||||||
"Role Name": "Role Name",
|
"No permissions": "No permissions",
|
||||||
"Type": "Type",
|
|
||||||
"Users": "Users",
|
|
||||||
"System Role": "System Role",
|
|
||||||
"System": "System",
|
|
||||||
"Custom": "Custom",
|
|
||||||
"Edit": "Edit",
|
|
||||||
"Are you sure you want to delete this role?": "Are you sure you want to delete this role?",
|
|
||||||
"Delete": "Delete",
|
|
||||||
"Protected": "Protected",
|
|
||||||
"No roles found.": "No roles found.",
|
"No roles found.": "No roles found.",
|
||||||
"Create Role": "Create Role",
|
"Create Role": "Create Role",
|
||||||
"Edit Role": "Edit Role",
|
"Edit Role": "Edit Role",
|
||||||
|
"Update existing role and permissions.": "Update existing role and permissions.",
|
||||||
|
"Create a new role and assign permissions.": "Create a new role and assign permissions.",
|
||||||
"Enter role name": "Enter role name",
|
"Enter role name": "Enter role name",
|
||||||
|
"Add Role": "Add Role",
|
||||||
|
"Role Name": "Role Name",
|
||||||
|
"Type": "Type",
|
||||||
|
"Permissions": "Permissions",
|
||||||
|
"Users": "Users",
|
||||||
|
"System role name cannot be modified.": "System role name cannot be modified.",
|
||||||
|
"members": "Member Management",
|
||||||
|
"machines": "Machine Management",
|
||||||
|
"app": "APP Management",
|
||||||
|
"warehouses": "Warehouse Management",
|
||||||
|
"sales": "Sales Management",
|
||||||
|
"analysis": "Analysis Management",
|
||||||
|
"audit": "Audit Management",
|
||||||
|
"data-config": "Data Configuration",
|
||||||
|
"remote": "Remote Management",
|
||||||
|
"line": "Line Management",
|
||||||
|
"reservation": "Reservation System",
|
||||||
|
"special-permission": "Special Permission",
|
||||||
|
"companies": "Customer Management",
|
||||||
|
"accounts": "Account Management",
|
||||||
|
"roles": "Role Settings",
|
||||||
|
"Role Settings": "Role Settings",
|
||||||
"No login history yet": "No login history yet",
|
"No login history yet": "No login history yet",
|
||||||
"Signed in as": "Signed in as",
|
"Signed in as": "Signed in as",
|
||||||
"Logout": "Logout",
|
"Logout": "Logout",
|
||||||
|
|||||||
68
lang/ja.json
68
lang/ja.json
@@ -148,22 +148,39 @@
|
|||||||
"AI Prediction": "AI予測",
|
"AI Prediction": "AI予測",
|
||||||
"Roles": "ロール",
|
"Roles": "ロール",
|
||||||
"Role Management": "ロール管理",
|
"Role Management": "ロール管理",
|
||||||
"Define and manage security roles for the system.": "システムのセキュリティロールを定義および管理します。",
|
"Define and manage security roles and permissions.": "システムのセキュリティロールと権限を定義および管理します。",
|
||||||
|
"Search roles...": "ロールを検索...",
|
||||||
|
"No permissions": "権限項目なし",
|
||||||
|
"No roles found.": "ロールが見つかりませんでした。",
|
||||||
|
"Create Role": "ロール作成",
|
||||||
|
"Edit Role": "ロール編集",
|
||||||
|
"Update existing role and permissions.": "既存のロールと権限を更新します。",
|
||||||
|
"Create a new role and assign permissions.": "新しいロールを作成し、権限を割り当てます。",
|
||||||
|
"Enter role name": "ロール名を入力してください",
|
||||||
"Add Role": "ロールを追加",
|
"Add Role": "ロールを追加",
|
||||||
"Role Name": "ロール名",
|
"Role Name": "ロール名",
|
||||||
"Type": "タイプ",
|
"Type": "タイプ",
|
||||||
|
"Permissions": "権限",
|
||||||
"Users": "ユーザー数",
|
"Users": "ユーザー数",
|
||||||
"System Role": "システムロール",
|
"System role name cannot be modified.": "システムロール名は変更できません。",
|
||||||
"System": "システム",
|
"Menu Permissions": "メニュー権限",
|
||||||
"Custom": "カスタム",
|
"Save Changes": "変更を保存",
|
||||||
"Edit": "編集",
|
"members": "会員管理",
|
||||||
"Are you sure you want to delete this role?": "このロールを削除してもよろしいですか?",
|
"machines": "機台管理",
|
||||||
"Delete": "削除",
|
"app": "APP管理",
|
||||||
"Protected": "保護済み",
|
"warehouses": "倉庫管理",
|
||||||
"No roles found.": "ロールが見見つかりません。",
|
"sales": "販売管理",
|
||||||
"Create Role": "ロールの作成",
|
"analysis": "分析管理",
|
||||||
"Edit Role": "ロールの編集",
|
"audit": "監査管理",
|
||||||
"Enter role name": "ロール名を入力してください",
|
"data-config": "データ設定",
|
||||||
|
"remote": "リモート管理",
|
||||||
|
"line": "Line管理",
|
||||||
|
"reservation": "予約システム",
|
||||||
|
"special-permission": "特別権限",
|
||||||
|
"companies": "顧客管理",
|
||||||
|
"accounts": "アカウント管理",
|
||||||
|
"roles": "ロール設定",
|
||||||
|
"Role Settings": "ロール設定",
|
||||||
"No login history yet": "ログイン履歴はまだありません",
|
"No login history yet": "ログイン履歴はまだありません",
|
||||||
"Signed in as": "ログイン中",
|
"Signed in as": "ログイン中",
|
||||||
"Logout": "ログアウト",
|
"Logout": "ログアウト",
|
||||||
@@ -172,23 +189,23 @@
|
|||||||
"Total Logins": "総ログイン数",
|
"Total Logins": "総ログイン数",
|
||||||
"Account Status": "アカウント状態",
|
"Account Status": "アカウント状態",
|
||||||
"Active": "アクティブ",
|
"Active": "アクティブ",
|
||||||
"Customer Management": "客戶管理",
|
"Customer Management": "顧客管理",
|
||||||
"Manage all tenant accounts and validity": "すべてのテナントアカウントと有効期限を管理します",
|
"Manage all tenant accounts and validity": "すべてのテナントアカウントと有効期限を管理します",
|
||||||
"Add Customer": "客戶を追加",
|
"Add Customer": "顧客を追加",
|
||||||
"Total Customers": "客戶総数",
|
"Total Customers": "顧客総数",
|
||||||
"Expired / Disabled": "期限切れ / 停止中",
|
"Expired / Disabled": "期限切れ / 停止中",
|
||||||
"Search customers...": "客戶を検索...",
|
"Search customers...": "顧客を検索...",
|
||||||
"All": "すべて",
|
"All": "すべて",
|
||||||
"Disabled": "停止中",
|
"Disabled": "停止中",
|
||||||
"Customer Info": "客戶情報",
|
"Customer Info": "顧客情報",
|
||||||
"Accounts / Machines": "アカウント / 機台",
|
"Accounts / Machines": "アカウント / 機台",
|
||||||
"Valid Until": "有効期限",
|
"Valid Until": "有効期限",
|
||||||
"Actions": "操作",
|
"Actions": "操作",
|
||||||
"Permanent": "永久認可",
|
"Permanent": "永久認可",
|
||||||
"Are you sure to delete this customer?": "この客戶を削除してもよろしいですか?",
|
"Are you sure to delete this customer?": "この顧客を削除してもよろしいですか?",
|
||||||
"No customers found": "客戶が見つかりません",
|
"No customers found": "顧客が見つかりません",
|
||||||
"Edit Customer": "客戶を編集",
|
"Edit Customer": "顧客を編集",
|
||||||
"Update Customer": "客戶を更新",
|
"Update Customer": "顧客を更新",
|
||||||
"Create": "作成",
|
"Create": "作成",
|
||||||
"Company Name": "会社名",
|
"Company Name": "会社名",
|
||||||
"Company Code": "会社コード",
|
"Company Code": "会社コード",
|
||||||
@@ -198,9 +215,9 @@
|
|||||||
"Contact Phone": "連絡先電話番号",
|
"Contact Phone": "連絡先電話番号",
|
||||||
"Contact Email": "連絡先メールアドレス",
|
"Contact Email": "連絡先メールアドレス",
|
||||||
"Notes": "備考",
|
"Notes": "備考",
|
||||||
"Customer created successfully.": "客戶が正常に作成されました。",
|
"Customer created successfully.": "顧客が正常に作成されました。",
|
||||||
"Customer updated successfully.": "客戶が正常に更新されました。",
|
"Customer updated successfully.": "顧客が正常に更新されました。",
|
||||||
"Customer deleted successfully.": "客戶が正常に削除されました。",
|
"Customer deleted successfully.": "顧客が正常に削除されました。",
|
||||||
"Cannot delete company with active accounts.": "アクティブなアカウントを持つ会社は削除できません。",
|
"Cannot delete company with active accounts.": "アクティブなアカウントを持つ会社は削除できません。",
|
||||||
"Contract Until (Optional)": "契約期限 (任意)",
|
"Contract Until (Optional)": "契約期限 (任意)",
|
||||||
"Company Information": "会社情報",
|
"Company Information": "会社情報",
|
||||||
@@ -229,8 +246,7 @@
|
|||||||
"Audit Permissions": "監査管理權限",
|
"Audit Permissions": "監査管理權限",
|
||||||
"Remote Permissions": "リモート管理權限",
|
"Remote Permissions": "リモート管理權限",
|
||||||
"Line Permissions": "Line管理權限",
|
"Line Permissions": "Line管理權限",
|
||||||
"Company": "所属客戶",
|
"Company": "所属顧客",
|
||||||
"Save Changes": "変更を保存",
|
|
||||||
"User": "一般ユーザー",
|
"User": "一般ユーザー",
|
||||||
"Admin": "管理者",
|
"Admin": "管理者",
|
||||||
"Super Admin": "スーパー管理者",
|
"Super Admin": "スーパー管理者",
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
"Permanently Delete Account": "永久刪除帳號",
|
"Permanently Delete Account": "永久刪除帳號",
|
||||||
"Password": "密碼",
|
"Password": "密碼",
|
||||||
"Enter your password to confirm": "請輸入您的密碼以確認",
|
"Enter your password to confirm": "請輸入您的密碼以確認",
|
||||||
|
|
||||||
"Dashboard": "儀表板",
|
"Dashboard": "儀表板",
|
||||||
"Connectivity Status": "連線狀態概況",
|
"Connectivity Status": "連線狀態概況",
|
||||||
"Real-time status monitoring": "即時監控機台連線動態",
|
"Real-time status monitoring": "即時監控機台連線動態",
|
||||||
@@ -148,22 +147,37 @@
|
|||||||
"AI Prediction": "AI智能預測",
|
"AI Prediction": "AI智能預測",
|
||||||
"Roles": "角色設定",
|
"Roles": "角色設定",
|
||||||
"Role Management": "角色管理",
|
"Role Management": "角色管理",
|
||||||
"Define and manage security roles for the system.": "定義與管理系統的安全角色。",
|
"Define and manage security roles and permissions.": "定義並管理系統安全角色與權限。",
|
||||||
"Add Role": "新增角色",
|
"Search roles...": "搜尋角色...",
|
||||||
"Role Name": "角色名稱",
|
"No permissions": "無權限項目",
|
||||||
"Type": "類型",
|
|
||||||
"Users": "使用者人數",
|
|
||||||
"System Role": "系統角色",
|
|
||||||
"System": "系統",
|
|
||||||
"Custom": "自定義",
|
|
||||||
"Edit": "編輯",
|
|
||||||
"Are you sure you want to delete this role?": "您確定要刪除此角色嗎?",
|
|
||||||
"Delete": "刪除",
|
|
||||||
"Protected": "受保護",
|
|
||||||
"No roles found.": "找不到角色資料。",
|
"No roles found.": "找不到角色資料。",
|
||||||
"Create Role": "建立角色",
|
"Create Role": "建立角色",
|
||||||
"Edit Role": "編輯角色",
|
"Edit Role": "編輯角色",
|
||||||
|
"Update existing role and permissions.": "更新現有角色與權限設定。",
|
||||||
|
"Create a new role and assign permissions.": "建立新角色並分配對應權限。",
|
||||||
"Enter role name": "請輸入角色名稱",
|
"Enter role name": "請輸入角色名稱",
|
||||||
|
"Add Role": "新增角色",
|
||||||
|
"Role Name": "角色名稱",
|
||||||
|
"Type": "類型",
|
||||||
|
"Permissions": "權限",
|
||||||
|
"Users": "帳號數",
|
||||||
|
"System role name cannot be modified.": "內建系統角色的名稱無法修改。",
|
||||||
|
"members": "會員管理",
|
||||||
|
"machines": "機台管理",
|
||||||
|
"app": "APP 管理",
|
||||||
|
"warehouses": "倉庫管理",
|
||||||
|
"sales": "銷售管理",
|
||||||
|
"analysis": "分析管理",
|
||||||
|
"audit": "稽核管理",
|
||||||
|
"data-config": "資料設定",
|
||||||
|
"remote": "遠端管理",
|
||||||
|
"line": "Line 管理",
|
||||||
|
"reservation": "預約系統",
|
||||||
|
"special-permission": "特殊權限",
|
||||||
|
"companies": "客戶管理",
|
||||||
|
"accounts": "帳號管理",
|
||||||
|
"roles": "角色設定",
|
||||||
|
"Role Settings": "角色設定",
|
||||||
"No login history yet": "尚無登入紀錄",
|
"No login history yet": "尚無登入紀錄",
|
||||||
"Signed in as": "登入身份",
|
"Signed in as": "登入身份",
|
||||||
"Logout": "登出",
|
"Logout": "登出",
|
||||||
@@ -244,5 +258,10 @@
|
|||||||
"to": "至",
|
"to": "至",
|
||||||
"of": "總計",
|
"of": "總計",
|
||||||
"items": "筆項目",
|
"items": "筆項目",
|
||||||
"Showing": "顯示第"
|
"Showing": "顯示第",
|
||||||
}
|
"Full Name": "全名",
|
||||||
|
"super-admin": "超級管理員",
|
||||||
|
"admin": "管理員",
|
||||||
|
"user": "一般用戶",
|
||||||
|
"Product Status": "商品狀態"
|
||||||
|
}
|
||||||
@@ -73,19 +73,9 @@
|
|||||||
<input type="text" name="search" value="{{ request('search') }}"
|
<input type="text" name="search" value="{{ request('search') }}"
|
||||||
class="py-3 pl-12 pr-6 block w-64 border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 rounded-2xl text-sm font-bold text-slate-700 dark:text-slate-200 placeholder-slate-400 dark:placeholder-slate-500 focus:ring-4 focus:ring-cyan-500/10 focus:border-cyan-500 transition-all outline-none"
|
class="py-3 pl-12 pr-6 block w-64 border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 rounded-2xl text-sm font-bold text-slate-700 dark:text-slate-200 placeholder-slate-400 dark:placeholder-slate-500 focus:ring-4 focus:ring-cyan-500/10 focus:border-cyan-500 transition-all outline-none"
|
||||||
placeholder="{{ __('Search customers...') }}">
|
placeholder="{{ __('Search customers...') }}">
|
||||||
|
<input type="hidden" name="per_page" value="{{ request('per_page', 10) }}">
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="flex items-center gap-4">
|
|
||||||
<form action="{{ route('admin.permission.companies.index') }}" method="GET" class="flex items-center gap-2">
|
|
||||||
@if(request('search'))<input type="hidden" name="search" value="{{ request('search') }}">@endif
|
|
||||||
@if(request('status'))<input type="hidden" name="status" value="{{ request('status') }}">@endif
|
|
||||||
<select name="limit" onchange="this.form.submit()" class="luxury-select text-[11px] py-2 px-3">
|
|
||||||
<option value="10" {{ request('limit') == 10 ? 'selected' : '' }}>10</option>
|
|
||||||
<option value="25" {{ request('limit') == 25 ? 'selected' : '' }}>25</option>
|
|
||||||
<option value="50" {{ request('limit') == 50 ? 'selected' : '' }}>50</option>
|
|
||||||
<option value="100" {{ request('limit') == 100 ? 'selected' : '' }}>100</option>
|
|
||||||
</select>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="flex items-center p-1 bg-slate-100/50 dark:bg-slate-900/50 backdrop-blur-md rounded-2xl border border-slate-200/50 dark:border-slate-700/50">
|
class="flex items-center p-1 bg-slate-100/50 dark:bg-slate-900/50 backdrop-blur-md rounded-2xl border border-slate-200/50 dark:border-slate-700/50">
|
||||||
@@ -103,7 +93,6 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="w-full text-left border-separate border-spacing-y-0">
|
<table class="w-full text-left border-separate border-spacing-y-0">
|
||||||
|
|||||||
@@ -129,16 +129,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form action="{{ route('admin.dashboard') }}" method="GET" class="flex flex-wrap items-center gap-4">
|
<form action="{{ route('admin.dashboard') }}" method="GET" class="flex flex-wrap items-center gap-4">
|
||||||
<div class="flex items-center gap-x-2">
|
|
||||||
<span class="text-[11px] font-black text-slate-400 uppercase tracking-widest hidden sm:inline">{{ __('Show') }}:</span>
|
|
||||||
<select name="limit" onchange="this.form.submit()" class="luxury-select py-3 min-w-[100px]">
|
|
||||||
<option value="10" {{ request('limit') == 10 ? 'selected' : '' }}>10</option>
|
|
||||||
<option value="25" {{ request('limit') == 25 ? 'selected' : '' }}>25</option>
|
|
||||||
<option value="50" {{ request('limit') == 50 ? 'selected' : '' }}>50</option>
|
|
||||||
<option value="100" {{ request('limit') == 100 ? 'selected' : '' }}>100</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="relative group">
|
<div class="relative group">
|
||||||
<span class="absolute inset-y-0 left-0 flex items-center pl-4 pointer-events-none">
|
<span class="absolute inset-y-0 left-0 flex items-center pl-4 pointer-events-none">
|
||||||
<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="3" stroke-linecap="round" stroke-linejoin="round">
|
<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="3" stroke-linecap="round" stroke-linejoin="round">
|
||||||
@@ -147,6 +137,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
<input type="text" name="search" value="{{ request('search') }}" class="py-3 pl-12 pr-6 block w-64 border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 rounded-2xl text-sm font-bold text-slate-700 dark:text-slate-200 placeholder-slate-400 dark:placeholder-slate-500 focus:ring-4 focus:ring-cyan-500/10 focus:border-cyan-500 transition-all outline-none" placeholder="{{ __('Quick search...') }}">
|
<input type="text" name="search" value="{{ request('search') }}" class="py-3 pl-12 pr-6 block w-64 border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 rounded-2xl text-sm font-bold text-slate-700 dark:text-slate-200 placeholder-slate-400 dark:placeholder-slate-500 focus:ring-4 focus:ring-cyan-500/10 focus:border-cyan-500 transition-all outline-none" placeholder="{{ __('Quick search...') }}">
|
||||||
|
<input type="hidden" name="per_page" value="{{ request('per_page', 10) }}">
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -21,7 +21,10 @@
|
|||||||
},
|
},
|
||||||
openEditModal(user) {
|
openEditModal(user) {
|
||||||
this.editing = true;
|
this.editing = true;
|
||||||
this.currentUser = { ...user };
|
this.currentUser = {
|
||||||
|
...user,
|
||||||
|
role: user.roles && user.roles.length > 0 ? user.roles[0].name : 'user'
|
||||||
|
};
|
||||||
this.showModal = true;
|
this.showModal = true;
|
||||||
}
|
}
|
||||||
}">
|
}">
|
||||||
@@ -49,6 +52,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
<input type="text" name="search" value="{{ request('search') }}" class="py-3 pl-12 pr-6 block w-full md:w-80 luxury-input" placeholder="{{ __('Search users...') }}">
|
<input type="text" name="search" value="{{ request('search') }}" class="py-3 pl-12 pr-6 block w-full md:w-80 luxury-input" placeholder="{{ __('Search users...') }}">
|
||||||
|
<input type="hidden" name="per_page" value="{{ request('per_page', 10) }}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if(auth()->user()->isSystemAdmin())
|
@if(auth()->user()->isSystemAdmin())
|
||||||
@@ -60,12 +64,6 @@
|
|||||||
</select>
|
</select>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<select name="limit" onchange="this.form.submit()" class="luxury-select w-full md:w-auto text-[11px]">
|
|
||||||
<option value="10" {{ request('limit') == 10 ? 'selected' : '' }}>10</option>
|
|
||||||
<option value="25" {{ request('limit') == 25 ? 'selected' : '' }}>25</option>
|
|
||||||
<option value="50" {{ request('limit') == 50 ? 'selected' : '' }}>50</option>
|
|
||||||
<option value="100" {{ request('limit') == 100 ? 'selected' : '' }}>100</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
@@ -211,9 +209,9 @@
|
|||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<label class="text-xs font-black text-slate-500 uppercase tracking-widest pl-1">{{ __('Role') }}</label>
|
<label class="text-xs font-black text-slate-500 uppercase tracking-widest pl-1">{{ __('Role') }}</label>
|
||||||
<select name="role" x-model="currentUser.role" class="luxury-select">
|
<select name="role" x-model="currentUser.role" class="luxury-select">
|
||||||
<option value="user">{{ __('User') }}</option>
|
@foreach($roles as $role)
|
||||||
<option value="admin">{{ __('Admin') }}</option>
|
<option value="{{ $role->name }}">{{ __($role->name) }}</option>
|
||||||
<option value="super-admin">{{ __('Super Admin') }}</option>
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
|
|||||||
@@ -18,10 +18,10 @@
|
|||||||
@if(request('status'))
|
@if(request('status'))
|
||||||
<input type="hidden" name="status" value="{{ request('status') }}">
|
<input type="hidden" name="status" value="{{ request('status') }}">
|
||||||
@endif
|
@endif
|
||||||
<select name="limit" onchange="this.form.submit()" class="h-9 text-[11px] font-black bg-slate-50 dark:bg-slate-800 border-slate-200 dark:border-slate-700 rounded-lg focus:ring-cyan-500/20 focus:border-cyan-500 transition-all">
|
<select name="per_page" onchange="this.form.submit()" class="h-9 text-[11px] font-black bg-slate-50 dark:bg-slate-800 border-slate-200 dark:border-slate-700 rounded-lg focus:ring-cyan-500/20 focus:border-cyan-500 transition-all">
|
||||||
@foreach([10, 25, 50, 100] as $size)
|
<option value="20" {{ request('per_page') == 20 ? 'selected' : '' }}>20 {{ __('Items') }}</option>
|
||||||
<option value="{{ $size }}" {{ request('limit') == $size ? 'selected' : '' }}>{{ $size }} {{ __('Items') }}</option>
|
<option value="50" {{ request('per_page') == 50 ? 'selected' : '' }}>50 {{ __('Items') }}</option>
|
||||||
@endforeach
|
<option value="100" {{ request('per_page') == 100 ? 'selected' : '' }}>100 {{ __('Items') }}</option>
|
||||||
</select>
|
</select>
|
||||||
</form>
|
</form>
|
||||||
<div class="flex space-x-2">
|
<div class="flex space-x-2">
|
||||||
|
|||||||
@@ -42,9 +42,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">筆數</label>
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">筆數</label>
|
||||||
<select name="limit" class="h-9 text-[11px] font-black bg-slate-50 dark:bg-slate-800 border-slate-200 dark:border-slate-700 rounded-lg focus:ring-cyan-500/20 focus:border-cyan-500 transition-all">
|
<select name="per_page" class="h-9 text-[11px] font-black bg-slate-50 dark:bg-slate-800 border-slate-200 dark:border-slate-700 rounded-lg focus:ring-cyan-500/20 focus:border-cyan-500 transition-all">
|
||||||
@foreach([10, 20, 50, 100] as $size)
|
@foreach([20, 50, 100, 200] as $size)
|
||||||
<option value="{{ $size }}" {{ request('limit', 20) == $size ? 'selected' : '' }}>{{ $size }} 筆</option>
|
<option value="{{ $size }}" {{ request('per_page', 20) == $size ? 'selected' : '' }}>{{ $size }} 筆</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,11 +6,13 @@
|
|||||||
isEdit: false,
|
isEdit: false,
|
||||||
roleId: '',
|
roleId: '',
|
||||||
roleName: '',
|
roleName: '',
|
||||||
|
rolePermissions: [],
|
||||||
modalTitle: '{{ __('Create Role') }}',
|
modalTitle: '{{ __('Create Role') }}',
|
||||||
openModal(edit = false, id = '', name = '') {
|
openModal(edit = false, id = '', name = '', permissions = []) {
|
||||||
this.isEdit = edit;
|
this.isEdit = edit;
|
||||||
this.roleId = id;
|
this.roleId = id;
|
||||||
this.roleName = name;
|
this.roleName = name;
|
||||||
|
this.rolePermissions = Array.isArray(permissions) ? permissions : (typeof permissions === 'string' ? JSON.parse(permissions) : []);
|
||||||
this.modalTitle = edit ? '{{ __('Edit Role') }}' : '{{ __('Create Role') }}';
|
this.modalTitle = edit ? '{{ __('Edit Role') }}' : '{{ __('Create Role') }}';
|
||||||
this.showModal = true;
|
this.showModal = true;
|
||||||
}
|
}
|
||||||
@@ -19,10 +21,10 @@
|
|||||||
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
|
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-3xl font-black text-slate-800 dark:text-white tracking-tight font-display">{{ __('Roles') }}</h1>
|
<h1 class="text-3xl font-black text-slate-800 dark:text-white tracking-tight font-display">{{ __('Roles') }}</h1>
|
||||||
<p class="text-sm font-bold text-slate-500 dark:text-slate-400 mt-1 uppercase tracking-widest">{{ __('Define and manage security roles for the system.') }}</p>
|
<p class="text-sm font-bold text-slate-500 dark:text-slate-400 mt-1 uppercase tracking-widest">{{ __('Define and manage security roles and permissions.') }}</p>
|
||||||
</div>
|
</div>
|
||||||
<button @click="openModal()" class="btn-luxury-primary">
|
<button @click="openModal()" class="btn-luxury-primary text-sm">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg>
|
||||||
<span>{{ __('Add Role') }}</span>
|
<span>{{ __('Add Role') }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -32,22 +34,13 @@
|
|||||||
<div class="flex flex-col md:flex-row md:items-center justify-between gap-6">
|
<div class="flex flex-col md:flex-row md:items-center justify-between gap-6">
|
||||||
<form action="{{ route('admin.permission.roles') }}" method="GET" class="relative group">
|
<form action="{{ route('admin.permission.roles') }}" method="GET" class="relative group">
|
||||||
<span class="absolute inset-y-0 left-0 flex items-center pl-4 pointer-events-none">
|
<span class="absolute inset-y-0 left-0 flex items-center pl-4 pointer-events-none">
|
||||||
<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="3" stroke-linecap="round" stroke-linejoin="round">
|
<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">
|
||||||
<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" name="search" value="{{ request('search') }}" class="py-2.5 pl-12 pr-6 block w-full md:w-80 luxury-input" placeholder="{{ __('Search roles...') }}">
|
<input type="text" name="search" value="{{ request('search') }}" class="py-2.5 pl-12 pr-6 block w-full md:w-80 luxury-input" placeholder="{{ __('Search roles...') }}">
|
||||||
</form>
|
<input type="hidden" name="per_page" value="{{ request('per_page', 10) }}">
|
||||||
|
|
||||||
<form action="{{ route('admin.permission.roles') }}" method="GET" class="flex items-center gap-3">
|
|
||||||
@if(request('search'))<input type="hidden" name="search" value="{{ request('search') }}">@endif
|
|
||||||
<label class="text-[11px] font-black text-slate-400 uppercase tracking-widest">{{ __('Show') }}</label>
|
|
||||||
<select name="limit" onchange="this.form.submit()" class="luxury-select py-1.5 px-3 text-[11px] min-w-[70px]">
|
|
||||||
<option value="10" {{ request('limit') == 10 ? 'selected' : '' }}>10</option>
|
|
||||||
<option value="25" {{ request('limit') == 25 ? 'selected' : '' }}>25</option>
|
|
||||||
<option value="50" {{ request('limit') == 50 ? 'selected' : '' }}>50</option>
|
|
||||||
</select>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -60,6 +53,7 @@
|
|||||||
<tr class="border-b border-slate-100 dark:border-slate-700">
|
<tr class="border-b border-slate-100 dark:border-slate-700">
|
||||||
<th class="px-6 py-5 text-sm font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest">{{ __('Role Name') }}</th>
|
<th class="px-6 py-5 text-sm font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest">{{ __('Role Name') }}</th>
|
||||||
<th class="px-6 py-5 text-sm font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest">{{ __('Type') }}</th>
|
<th class="px-6 py-5 text-sm font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest">{{ __('Type') }}</th>
|
||||||
|
<th class="px-6 py-5 text-sm font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest">{{ __('Permissions') }}</th>
|
||||||
<th class="px-6 py-5 text-sm font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest text-center">{{ __('Users') }}</th>
|
<th class="px-6 py-5 text-sm font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest text-center">{{ __('Users') }}</th>
|
||||||
<th class="px-6 py-5 text-sm font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest text-right">{{ __('Actions') }}</th>
|
<th class="px-6 py-5 text-sm font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest text-right">{{ __('Actions') }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -69,10 +63,13 @@
|
|||||||
<tr class="hover:bg-slate-50/80 dark:hover:bg-slate-800/50 transition-colors group">
|
<tr class="hover:bg-slate-50/80 dark:hover:bg-slate-800/50 transition-colors group">
|
||||||
<td class="px-6 py-5">
|
<td class="px-6 py-5">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="w-9 h-9 rounded-xl flex items-center justify-center bg-slate-50 dark:bg-slate-800 text-slate-400 group-hover:bg-cyan-500/10 group-hover:text-cyan-500 transition-all duration-300">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" /></svg>
|
||||||
|
</div>
|
||||||
<span class="text-sm font-bold text-slate-700 dark:text-slate-200">{{ $role->name }}</span>
|
<span class="text-sm font-bold text-slate-700 dark:text-slate-200">{{ $role->name }}</span>
|
||||||
@if($role->is_system)
|
@if($role->is_system)
|
||||||
<span class="p-1.5 bg-cyan-50 dark:bg-cyan-900/30 text-cyan-600 dark:text-cyan-400 rounded-lg tooltip" title="{{ __('System Role') }}">
|
<span class="p-1.5 bg-cyan-50 dark:bg-cyan-900/30 text-cyan-600 dark:text-cyan-400 rounded-lg tooltip" title="{{ __('System Role') }}">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
|
||||||
</span>
|
</span>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@@ -88,31 +85,41 @@
|
|||||||
</span>
|
</span>
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
|
<td class="px-6 py-5">
|
||||||
|
<div class="flex flex-wrap gap-1 max-w-xs">
|
||||||
|
@forelse($role->permissions->take(5) as $permission)
|
||||||
|
<span class="px-2 py-0.5 text-[10px] bg-slate-100 dark:bg-slate-800 text-slate-500 rounded uppercase font-bold">{{ __(str_replace('menu.', '', $permission->name)) }}</span>
|
||||||
|
@empty
|
||||||
|
<span class="text-xs text-slate-400 italic">{{ __('No permissions') }}</span>
|
||||||
|
@endforelse
|
||||||
|
@if($role->permissions->count() > 5)
|
||||||
|
<span class="px-2 py-0.5 text-[10px] bg-slate-100 dark:bg-slate-800 text-slate-400 rounded uppercase font-bold">+{{ $role->permissions->count() - 5 }}</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
<td class="px-6 py-5 text-center">
|
<td class="px-6 py-5 text-center">
|
||||||
<span class="text-sm font-black text-slate-600 dark:text-slate-400">{{ $role->users_count }}</span>
|
<span class="text-sm font-black text-slate-600 dark:text-slate-400">{{ $role->users()->count() }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-5 text-right">
|
<td class="px-6 py-5 text-right">
|
||||||
<div class="flex items-center justify-end gap-2">
|
<div class="flex items-center justify-end gap-2 text-slate-400">
|
||||||
@if(!$role->is_system)
|
<button @click="openModal(true, '{{ $role->id }}', '{{ $role->name }}', {{ $role->permissions->pluck('name') }})" class="p-2 rounded-lg bg-slate-50 dark:bg-slate-800 hover:text-cyan-500 hover:bg-cyan-500/10 transition-all border border-transparent hover:border-cyan-500/20 shadow-sm tooltip" title="{{ __('Edit') }}">
|
||||||
<button @click="openModal(true, '{{ $role->id }}', '{{ $role->name }}')" class="p-2 rounded-lg bg-slate-50 dark:bg-slate-800 text-slate-400 hover:text-cyan-500 hover:bg-cyan-500/5 transition-all border border-transparent hover:border-cyan-500/20 tooltip" title="{{ __('Edit') }}">
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10"/></svg>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4.5 h-4.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/><path d="m15 5 4 4"/></svg>
|
|
||||||
</button>
|
</button>
|
||||||
<form action="{{ route('admin.permission.roles.destroy', $role->id) }}" method="POST" @submit.prevent="if(confirm('{{ __('Are you sure you want to delete this role?') }}')) $el.submit()" class="inline">
|
@if(!$role->is_system)
|
||||||
|
<form action="{{ route('admin.permission.roles.destroy', $role->id) }}" method="POST" @submit.prevent="if(confirm('{{ __('Are you sure you want to delete this role?') }}')) $el.submit()" class="inline text-slate-400">
|
||||||
@csrf
|
@csrf
|
||||||
@method('DELETE')
|
@method('DELETE')
|
||||||
<button type="submit" class="p-2 rounded-lg bg-slate-50 dark:bg-slate-800 text-slate-400 hover:text-rose-500 hover:bg-rose-500/5 transition-all border border-transparent hover:border-rose-500/20 tooltip" title="{{ __('Delete') }}">
|
<button type="submit" class="p-2 rounded-lg bg-slate-50 dark:bg-slate-800 hover:text-rose-500 hover:bg-rose-500/10 transition-all border border-transparent hover:border-rose-500/20 shadow-sm tooltip" title="{{ __('Delete') }}">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4.5 h-4.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/><line x1="10" x2="10" y1="11" y2="17"/><line x1="14" x2="14" y1="11" y2="17"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/><line x1="10" x2="10" y1="11" y2="17"/><line x1="14" x2="14" y1="11" y2="17"/></svg>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
@else
|
|
||||||
<span class="px-3 py-1 text-[11px] font-black uppercase tracking-widest text-slate-400 bg-slate-50 dark:bg-slate-800/50 rounded-lg border border-slate-200/50 dark:border-slate-700/50 italic">{{ __('Protected') }}</span>
|
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@empty
|
@empty
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4" class="px-6 py-20 text-center">
|
<td colspan="5" class="px-6 py-20 text-center">
|
||||||
<div class="flex flex-col items-center justify-center gap-4 text-slate-400">
|
<div class="flex flex-col items-center justify-center gap-4 text-slate-400">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-16 h-16 opacity-20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M12 8v8"/><path d="M8 12h8"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-16 h-16 opacity-20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M12 8v8"/><path d="M8 12h8"/></svg>
|
||||||
<p class="text-lg font-bold">{{ __('No roles found.') }}</p>
|
<p class="text-lg font-bold">{{ __('No roles found.') }}</p>
|
||||||
@@ -134,26 +141,87 @@
|
|||||||
<div class="fixed inset-0 z-[60] flex items-center justify-center p-4">
|
<div class="fixed inset-0 z-[60] flex items-center justify-center p-4">
|
||||||
<div @click="showModal = false" class="absolute inset-0 bg-slate-900/60 backdrop-blur-sm transition-opacity"></div>
|
<div @click="showModal = false" class="absolute inset-0 bg-slate-900/60 backdrop-blur-sm transition-opacity"></div>
|
||||||
|
|
||||||
<div class="relative w-full max-w-lg bg-white dark:bg-slate-900 rounded-2xl shadow-2xl overflow-hidden animate-luxury-in">
|
<div class="relative w-full max-w-3xl bg-white dark:bg-slate-900 rounded-3xl shadow-2xl overflow-hidden animate-luxury-in">
|
||||||
<div class="flex items-center justify-between p-6 border-b border-slate-100 dark:border-slate-800">
|
<div class="flex items-center justify-between p-8 border-b border-slate-100 dark:border-slate-800">
|
||||||
<h3 class="text-xl font-black text-slate-800 dark:text-white" x-text="modalTitle"></h3>
|
<div>
|
||||||
<button @click="showModal = false" class="text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 transition-colors">
|
<h3 class="text-2xl font-black text-slate-800 dark:text-white" x-text="modalTitle"></h3>
|
||||||
|
<p class="text-sm font-bold text-slate-400 mt-1" x-text="isEdit ? '{{ __('Update existing role and permissions.') }}' : '{{ __('Create a new role and assign permissions.') }}'"></p>
|
||||||
|
</div>
|
||||||
|
<button @click="showModal = false" class="p-2 rounded-xl hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 transition-all">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form :action="isEdit ? '{{ route('admin.permission.roles') }}/' + roleId : '{{ route('admin.permission.roles.store') }}'" method="POST" class="p-6 space-y-6">
|
<form :action="isEdit ? '{{ route('admin.permission.roles') }}/' + roleId : '{{ route('admin.permission.roles.store') }}'" method="POST">
|
||||||
@csrf
|
@csrf
|
||||||
<template x-if="isEdit"><input type="hidden" name="_method" value="PUT"></template>
|
<template x-if="isEdit"><input type="hidden" name="_method" value="PUT"></template>
|
||||||
|
|
||||||
<div class="space-y-2">
|
<div class="p-8 max-h-[65vh] overflow-y-auto custom-scrollbar">
|
||||||
<label class="text-sm font-black text-slate-700 dark:text-slate-300">{{ __('Role Name') }}</label>
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||||
<input type="text" name="name" x-model="roleName" required class="luxury-input w-full" :placeholder="'{{ __('Enter role name') }}'">
|
<!-- Left: Basic Info -->
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="text-xs font-black text-slate-400 uppercase tracking-widest pl-1">{{ __('Role Name') }}</label>
|
||||||
|
<input type="text" name="name" x-model="roleName" required class="luxury-input w-full" placeholder="{{ __('Enter role name') }}" :disabled="isEdit && {{ json_encode($roles->pluck('is_system', 'id')) }}[roleId]">
|
||||||
|
<template x-if="isEdit && {{ json_encode($roles->pluck('is_system', 'id')) }}[roleId]">
|
||||||
|
<p class="text-[10px] text-amber-500 font-bold mt-1 px-1 flex items-center gap-1.5">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></svg>
|
||||||
|
{{ __('System role name cannot be modified.') }}
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right: Permissions -->
|
||||||
|
<div class="space-y-6">
|
||||||
|
<label class="text-xs font-black text-slate-400 uppercase tracking-widest pl-1">{{ __('Menu Permissions') }}</label>
|
||||||
|
<div class="luxury-card border-slate-100 dark:border-slate-800 p-4 rounded-2xl grid grid-cols-1 gap-3">
|
||||||
|
@php
|
||||||
|
$icon_map = [
|
||||||
|
'members' => 'M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z',
|
||||||
|
'machines' => 'M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 01-2 2v4a2 2 0 012 2h14a2 2 0 012-2v-4a2 2 0 01-2-2m-2-4h.01M17 16h.01',
|
||||||
|
'app' => 'M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z',
|
||||||
|
'warehouses' => 'M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10',
|
||||||
|
'sales' => 'M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z',
|
||||||
|
'analysis' => 'M7 12l3-3 3 3 4-4M8 21l4-4 4 4M3 4h18M4 4h16v12a1 1 0 01-1 1H5a1 1 0 01-1-1V4z',
|
||||||
|
'audit' => 'M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z',
|
||||||
|
'data-config' => 'M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z',
|
||||||
|
'remote' => 'M5.636 18.364a9 9 0 010-12.728m12.728 0a9 9 0 010 12.728m-9.9-2.829a5 5 0 010-7.07m7.072 0a5 5 0 010 7.07M21 12a9 9 0 11-18 0 9 9 0 0118 0z',
|
||||||
|
'line' => 'M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z',
|
||||||
|
'reservation' => 'M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z',
|
||||||
|
'special-permission' => 'M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z',
|
||||||
|
'companies' => 'M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4',
|
||||||
|
'accounts' => 'M5.121 17.804A13.937 13.937 0 0112 16c2.5 0 4.847.655 6.879 1.804M15 10a3 3 0 11-6 0 3 3 0 016 0zm6 2a9 9 0 11-18 0 9 9 0 0118 0z',
|
||||||
|
'roles' => 'M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z',
|
||||||
|
];
|
||||||
|
@endphp
|
||||||
|
@foreach($all_permissions->get('menu', []) as $permission)
|
||||||
|
@php
|
||||||
|
$pure_name = str_replace('menu.', '', $permission->name);
|
||||||
|
@endphp
|
||||||
|
<label class="flex items-center gap-3 p-3 rounded-xl hover:bg-slate-50 dark:hover:bg-slate-800/50 cursor-pointer transition-all border border-transparent hover:border-slate-200 dark:hover:border-slate-700 group">
|
||||||
|
<div class="relative flex items-center">
|
||||||
|
<input type="checkbox" name="permissions[]" value="{{ $permission->name }}"
|
||||||
|
x-model="rolePermissions"
|
||||||
|
class="peer w-5 h-5 rounded-lg border-2 border-slate-200 dark:border-slate-700 text-cyan-500 focus:ring-cyan-500 focus:ring-offset-0 bg-transparent transition-all checked:border-cyan-500">
|
||||||
|
<svg class="absolute w-3.5 h-3.5 text-white opacity-0 peer-checked:opacity-100 left-0.5 pointer-events-none transition-opacity" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2.5">
|
||||||
|
<div class="w-7 h-7 rounded-lg flex items-center justify-center bg-slate-50 dark:bg-slate-800 text-slate-400 group-hover:bg-cyan-500/10 group-hover:text-cyan-500 transition-colors">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="{{ $icon_map[$pure_name] ?? 'M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z' }}" /></svg>
|
||||||
|
</div>
|
||||||
|
<span class="text-sm font-bold text-slate-600 dark:text-slate-300 group-hover:text-slate-900 dark:group-hover:text-white transition-colors">{{ __($pure_name) }}</span>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-end gap-3 mt-8">
|
<div class="p-8 bg-slate-50 dark:bg-slate-800/50 border-t border-slate-100 dark:border-slate-800 flex items-center justify-end gap-4">
|
||||||
<button type="button" @click="showModal = false" class="btn-luxury-ghost px-6 py-2.5 rounded-xl font-bold">{{ __('Cancel') }}</button>
|
<button type="button" @click="showModal = false" class="btn-luxury-ghost px-8 py-3 rounded-2xl font-black text-xs uppercase tracking-widest">{{ __('Cancel') }}</button>
|
||||||
<button type="submit" class="btn-luxury-primary px-8 py-2.5 rounded-xl font-bold">{{ __('Save Changes') }}</button>
|
<button type="submit" class="btn-luxury-primary px-10 py-3 rounded-2xl font-black text-xs uppercase tracking-widest shadow-xl shadow-cyan-500/20">{{ __('Save Changes') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -221,7 +221,7 @@
|
|||||||
<!-- End Sidebar -->
|
<!-- End Sidebar -->
|
||||||
|
|
||||||
<!-- Content -->
|
<!-- Content -->
|
||||||
<div class="w-full pt-6 lg:pt-10 px-4 sm:px-6 md:px-8 lg:pl-72">
|
<div class="w-full pt-6 lg:pt-10 pb-12 px-4 sm:px-6 md:px-8 lg:pl-72">
|
||||||
<x-breadcrumbs class="mb-4 hidden lg:flex" />
|
<x-breadcrumbs class="mb-4 hidden lg:flex" />
|
||||||
<main class="animate-fade-up">
|
<main class="animate-fade-up">
|
||||||
@yield('content')
|
@yield('content')
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
@can('menu.members')
|
||||||
{{-- 3. 會員管理 --}}
|
{{-- 3. 會員管理 --}}
|
||||||
<li x-data="{ open: localStorage.getItem('menu_members') === 'true' || {{ request()->routeIs('admin.members.*') || request()->routeIs('admin.membership-tiers.*') || request()->routeIs('admin.deposit-bonus-rules.*') || request()->routeIs('admin.point-rules.*') || request()->routeIs('admin.gift-definitions.*') ? 'true' : 'false' }} }">
|
<li x-data="{ open: localStorage.getItem('menu_members') === 'true' || {{ request()->routeIs('admin.members.*') || request()->routeIs('admin.membership-tiers.*') || request()->routeIs('admin.deposit-bonus-rules.*') || request()->routeIs('admin.point-rules.*') || request()->routeIs('admin.gift-definitions.*') ? 'true' : 'false' }} }">
|
||||||
<button type="button" @click="open = !open; localStorage.setItem('menu_members', open)" class="luxury-nav-item w-full text-start group">
|
<button type="button" @click="open = !open; localStorage.setItem('menu_members', open)" class="luxury-nav-item w-full text-start group">
|
||||||
@@ -42,7 +43,10 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
|
||||||
|
@can('menu.machines')
|
||||||
{{-- 4. 機台管理 --}}
|
{{-- 4. 機台管理 --}}
|
||||||
<li x-data="{ open: localStorage.getItem('menu_machines') === 'true' || {{ request()->routeIs('admin.machines.*') ? 'true' : 'false' }} }">
|
<li x-data="{ open: localStorage.getItem('menu_machines') === 'true' || {{ request()->routeIs('admin.machines.*') ? 'true' : 'false' }} }">
|
||||||
<button type="button" @click="open = !open; localStorage.setItem('menu_machines', open)" class="luxury-nav-item w-full text-start group">
|
<button type="button" @click="open = !open; localStorage.setItem('menu_machines', open)" class="luxury-nav-item w-full text-start group">
|
||||||
@@ -61,7 +65,10 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
|
||||||
|
@can('menu.app')
|
||||||
{{-- 5. APP管理 --}}
|
{{-- 5. APP管理 --}}
|
||||||
<li x-data="{ open: localStorage.getItem('menu_app') === 'true' || {{ request()->routeIs('admin.app.*') ? 'true' : 'false' }} }">
|
<li x-data="{ open: localStorage.getItem('menu_app') === 'true' || {{ request()->routeIs('admin.app.*') ? 'true' : 'false' }} }">
|
||||||
<button type="button" @click="open = !open; localStorage.setItem('menu_app', open)" class="luxury-nav-item w-full text-start group">
|
<button type="button" @click="open = !open; localStorage.setItem('menu_app', open)" class="luxury-nav-item w-full text-start group">
|
||||||
@@ -79,7 +86,10 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
|
||||||
|
@can('menu.warehouses')
|
||||||
{{-- 6. 倉庫管理 --}}
|
{{-- 6. 倉庫管理 --}}
|
||||||
<li x-data="{ open: localStorage.getItem('menu_warehouses') === 'true' || {{ request()->routeIs('admin.warehouses.*') ? 'true' : 'false' }} }">
|
<li x-data="{ open: localStorage.getItem('menu_warehouses') === 'true' || {{ request()->routeIs('admin.warehouses.*') ? 'true' : 'false' }} }">
|
||||||
<button type="button" @click="open = !open; localStorage.setItem('menu_warehouses', open)" class="luxury-nav-item w-full text-start group">
|
<button type="button" @click="open = !open; localStorage.setItem('menu_warehouses', open)" class="luxury-nav-item w-full text-start group">
|
||||||
@@ -102,7 +112,10 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
|
||||||
|
@can('menu.sales')
|
||||||
{{-- 7. 銷售管理 --}}
|
{{-- 7. 銷售管理 --}}
|
||||||
<li x-data="{ open: localStorage.getItem('menu_sales') === 'true' || {{ request()->routeIs('admin.sales.*') ? 'true' : 'false' }} }">
|
<li x-data="{ open: localStorage.getItem('menu_sales') === 'true' || {{ request()->routeIs('admin.sales.*') ? 'true' : 'false' }} }">
|
||||||
<button type="button" @click="open = !open; localStorage.setItem('menu_sales', open)" class="luxury-nav-item w-full text-start group">
|
<button type="button" @click="open = !open; localStorage.setItem('menu_sales', open)" class="luxury-nav-item w-full text-start group">
|
||||||
@@ -121,7 +134,10 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
|
||||||
|
@can('menu.analysis')
|
||||||
{{-- 8. 分析管理 --}}
|
{{-- 8. 分析管理 --}}
|
||||||
<li x-data="{ open: localStorage.getItem('menu_analysis') === 'true' || {{ request()->routeIs('admin.analysis.*') ? 'true' : 'false' }} }">
|
<li x-data="{ open: localStorage.getItem('menu_analysis') === 'true' || {{ request()->routeIs('admin.analysis.*') ? 'true' : 'false' }} }">
|
||||||
<button type="button" @click="open = !open; localStorage.setItem('menu_analysis', open)" class="luxury-nav-item w-full text-start group">
|
<button type="button" @click="open = !open; localStorage.setItem('menu_analysis', open)" class="luxury-nav-item w-full text-start group">
|
||||||
@@ -138,7 +154,10 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
|
||||||
|
@can('menu.audit')
|
||||||
{{-- 9. 稽核管理 --}}
|
{{-- 9. 稽核管理 --}}
|
||||||
<li x-data="{ open: localStorage.getItem('menu_audit') === 'true' || {{ request()->routeIs('admin.audit.*') ? 'true' : 'false' }} }">
|
<li x-data="{ open: localStorage.getItem('menu_audit') === 'true' || {{ request()->routeIs('admin.audit.*') ? 'true' : 'false' }} }">
|
||||||
<button type="button" @click="open = !open; localStorage.setItem('menu_audit', open)" class="luxury-nav-item w-full text-start group">
|
<button type="button" @click="open = !open; localStorage.setItem('menu_audit', open)" class="luxury-nav-item w-full text-start group">
|
||||||
@@ -154,7 +173,10 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
|
||||||
|
@can('menu.data-config')
|
||||||
{{-- 10. 資料設定 --}}
|
{{-- 10. 資料設定 --}}
|
||||||
<li x-data="{ open: localStorage.getItem('menu_data_config') === 'true' || {{ request()->routeIs('admin.data-config.*') ? 'true' : 'false' }} }">
|
<li x-data="{ open: localStorage.getItem('menu_data_config') === 'true' || {{ request()->routeIs('admin.data-config.*') ? 'true' : 'false' }} }">
|
||||||
<button type="button" @click="open = !open; localStorage.setItem('menu_data_config', open)" class="luxury-nav-item w-full text-start group">
|
<button type="button" @click="open = !open; localStorage.setItem('menu_data_config', open)" class="luxury-nav-item w-full text-start group">
|
||||||
@@ -166,7 +188,7 @@
|
|||||||
<ul class="luxury-submenu">
|
<ul class="luxury-submenu">
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.data-config.products') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.data-config.products') }}">{{ __('Product Management') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.data-config.products') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.data-config.products') }}">{{ __('Product Management') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.data-config.advertisements') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.data-config.advertisements') }}">{{ __('Advertisement Management') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.data-config.advertisements') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.data-config.advertisements') }}">{{ __('Advertisement Management') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.data-config.admin-products') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.data-config.admin-products') }}">{{ __('Admin Sellable Products') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.data-config.admin-products') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.data-config.admin-products') }}">{{ __('Product Status') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.data-config.sub-accounts') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.data-config.sub-accounts') }}">{{ __('Sub Accounts') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.data-config.sub-accounts') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.data-config.sub-accounts') }}">{{ __('Sub Accounts') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.data-config.sub-account-roles') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.data-config.sub-account-roles') }}">{{ __('Sub Account Roles') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.data-config.sub-account-roles') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.data-config.sub-account-roles') }}">{{ __('Sub Account Roles') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.data-config.points') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.data-config.points') }}">{{ __('Point Settings') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.data-config.points') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.data-config.points') }}">{{ __('Point Settings') }}</a></li>
|
||||||
@@ -174,8 +196,11 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@can('menu.remote')
|
||||||
{{-- 11. 遠端管理 --}}
|
{{-- 11. 遠端管理 --}}
|
||||||
<li x-data="{ open: localStorage.getItem('menu_remote') === 'true' || {{ request()->routeIs('admin.remote.*') ? 'true' : 'false' }} }">
|
<li x-data="{ open: localStorage.getItem('menu_remote') === 'true' || {{ request()->routeIs('admin.remote.*') ? 'true' : 'false' }} }">
|
||||||
<button type="button" @click="open = !open; localStorage.setItem('menu_remote', open)" class="luxury-nav-item w-full text-start group">
|
<button type="button" @click="open = !open; localStorage.setItem('menu_remote', open)" class="luxury-nav-item w-full text-start group">
|
||||||
@@ -195,7 +220,10 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
|
||||||
|
@can('menu.line')
|
||||||
{{-- 12. Line管理 --}}
|
{{-- 12. Line管理 --}}
|
||||||
<li x-data="{ open: localStorage.getItem('menu_line') === 'true' || {{ request()->routeIs('admin.line.*') ? 'true' : 'false' }} }">
|
<li x-data="{ open: localStorage.getItem('menu_line') === 'true' || {{ request()->routeIs('admin.line.*') ? 'true' : 'false' }} }">
|
||||||
<button type="button" @click="open = !open; localStorage.setItem('menu_line', open)" class="luxury-nav-item w-full text-start group">
|
<button type="button" @click="open = !open; localStorage.setItem('menu_line', open)" class="luxury-nav-item w-full text-start group">
|
||||||
@@ -205,16 +233,18 @@
|
|||||||
</button>
|
</button>
|
||||||
<div x-show="open" x-collapse>
|
<div x-show="open" x-collapse>
|
||||||
<ul class="luxury-submenu">
|
<ul class="luxury-submenu">
|
||||||
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.line.official-account') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.line.official-account') }}">{{ __('Official Account') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.line.members') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.line.members') }}">{{ __('Line Members') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.line.members') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.line.members') }}">{{ __('Line Members') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.line.machines') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.line.machines') }}">{{ __('Line Machines') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.line.machines') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.line.machines') }}">{{ __('Line Machines') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.line.products') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.line.products') }}">{{ __('Line Products') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.line.products') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.line.products') }}">{{ __('Line Products') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.line.official-account') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.line.official-account') }}">{{ __('Line Official Account') }}</a></li>
|
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.line.orders') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.line.orders') }}">{{ __('Line Orders') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.line.orders') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.line.orders') }}">{{ __('Line Orders') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.line.coupons') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.line.coupons') }}">{{ __('Line Coupons') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.line.coupons') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.line.coupons') }}">{{ __('Line Coupons') }}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
@can('menu.reservation')
|
||||||
{{-- 13. 預約系統 --}}
|
{{-- 13. 預約系統 --}}
|
||||||
<li x-data="{ open: localStorage.getItem('menu_reservation') === 'true' || {{ request()->routeIs('admin.reservation.*') ? 'true' : 'false' }} }">
|
<li x-data="{ open: localStorage.getItem('menu_reservation') === 'true' || {{ request()->routeIs('admin.reservation.*') ? 'true' : 'false' }} }">
|
||||||
<button type="button" @click="open = !open; localStorage.setItem('menu_reservation', open)" class="luxury-nav-item w-full text-start group">
|
<button type="button" @click="open = !open; localStorage.setItem('menu_reservation', open)" class="luxury-nav-item w-full text-start group">
|
||||||
@@ -224,18 +254,19 @@
|
|||||||
</button>
|
</button>
|
||||||
<div x-show="open" x-collapse>
|
<div x-show="open" x-collapse>
|
||||||
<ul class="luxury-submenu">
|
<ul class="luxury-submenu">
|
||||||
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.reservation.reservations') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.reservation.reservations') }}">{{ __('Reservation List') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.reservation.members') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.reservation.members') }}">{{ __('Reservation Members') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.reservation.members') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.reservation.members') }}">{{ __('Reservation Members') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.reservation.stores') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.reservation.stores') }}">{{ __('Store Management') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.reservation.stores') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.reservation.stores') }}">{{ __('Stores Management') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.reservation.time-slots') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.reservation.time-slots') }}">{{ __('Time Slots') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.reservation.time-slots') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.reservation.time-slots') }}">{{ __('Time Slots') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.reservation.venues') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.reservation.venues') }}">{{ __('Venue Management') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.reservation.venues') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.reservation.venues') }}">{{ __('Venues Management') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.reservation.coupons') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.reservation.coupons') }}">{{ __('Coupons') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.reservation.coupons') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.reservation.coupons') }}">{{ __('Reservation Coupons') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.reservation.reservations') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.reservation.reservations') }}">{{ __('Reservations') }}</a></li>
|
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.reservation.orders') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.reservation.orders') }}">{{ __('Reservation Orders') }}</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.reservation.orders') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.reservation.orders') }}">{{ __('Order Management') }}</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@endcan
|
||||||
|
|
||||||
@role('super-admin')
|
@can('menu.special-permission')
|
||||||
{{-- 14. 特殊權限 --}}
|
{{-- 14. 特殊權限 --}}
|
||||||
<li x-data="{ open: localStorage.getItem('menu_special_permission') === 'true' || {{ request()->routeIs('admin.special-permission.*') ? 'true' : 'false' }} }">
|
<li x-data="{ open: localStorage.getItem('menu_special_permission') === 'true' || {{ request()->routeIs('admin.special-permission.*') ? 'true' : 'false' }} }">
|
||||||
<button type="button" @click="open = !open; localStorage.setItem('menu_special_permission', open)" class="luxury-nav-item w-full text-start group">
|
<button type="button" @click="open = !open; localStorage.setItem('menu_special_permission', open)" class="luxury-nav-item w-full text-start group">
|
||||||
@@ -251,9 +282,9 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@endrole
|
@endcan
|
||||||
|
|
||||||
@role('super-admin')
|
@canany(['menu.companies', 'menu.accounts', 'menu.roles'])
|
||||||
{{-- 15. 權限設定 --}}
|
{{-- 15. 權限設定 --}}
|
||||||
<li x-data="{ open: localStorage.getItem('menu_permissions') === 'true' || {{ request()->routeIs('admin.permission.*') ? 'true' : 'false' }} }">
|
<li x-data="{ open: localStorage.getItem('menu_permissions') === 'true' || {{ request()->routeIs('admin.permission.*') ? 'true' : 'false' }} }">
|
||||||
<button type="button" @click="open = !open; localStorage.setItem('menu_permissions', open)" class="luxury-nav-item w-full text-start group">
|
<button type="button" @click="open = !open; localStorage.setItem('menu_permissions', open)" class="luxury-nav-item w-full text-start group">
|
||||||
@@ -263,21 +294,26 @@
|
|||||||
</button>
|
</button>
|
||||||
<div x-show="open" x-collapse>
|
<div x-show="open" x-collapse>
|
||||||
<ul class="luxury-submenu">
|
<ul class="luxury-submenu">
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.companies.*') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.permission.companies.index') }}">{{ __('Customer Management') }}</a></li>
|
@can('menu.companies')
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.accounts') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.permission.accounts') }}">{{ __('Account Management') }}</a></li>
|
<li><a class="flex items-center gap-x-3 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.companies.*') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.permission.companies.index') }}">
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.roles') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.permission.roles') }}">{{ __('Roles') }}</a></li>
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 shrink-0 transition-colors" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" /></svg>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.app-features') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.permission.app-features') }}">{{ __('APP Features') }}</a></li>
|
{{ __('Customer Management') }}
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.data-config') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.permission.data-config') }}">{{ __('Data Configuration') }}</a></li>
|
</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.sales') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.permission.sales') }}">{{ __('Sales') }}</a></li>
|
@endcan
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.machines') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.permission.machines') }}">{{ __('Machine Management') }}</a></li>
|
@can('menu.accounts')
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.warehouses') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.permission.warehouses') }}">{{ __('Warehouse Management') }}</a></li>
|
<li><a class="flex items-center gap-x-3 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.accounts') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.permission.accounts') }}">
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.analysis') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.permission.analysis') }}">{{ __('Analysis Management') }}</a></li>
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 shrink-0 transition-colors" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M5.121 17.804A13.937 13.937 0 0112 16c2.5 0 4.847.655 6.879 1.804M15 10a3 3 0 11-6 0 3 3 0 016 0zm6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.audit') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.permission.audit') }}">{{ __('Audit Management') }}</a></li>
|
{{ __('Account Management') }}
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.remote') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.permission.remote') }}">{{ __('Remote Management') }}</a></li>
|
</a></li>
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.line') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.line.members') }}">{{ __('Line Management') }}</a></li>
|
@endcan
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.others') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.permission.others') }}">{{ __('Others') }}</a></li>
|
@can('menu.roles')
|
||||||
<li><a class="flex items-center gap-x-3.5 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.ai-prediction') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.permission.ai-prediction') }}">{{ __('AI Prediction') }}</a></li>
|
<li><a class="flex items-center gap-x-3 py-2 px-2.5 text-sm transition-colors rounded-lg {{ request()->routeIs('admin.permission.roles') ? 'text-slate-900 dark:text-white bg-slate-100 dark:bg-white/5' : 'text-slate-500 hover:text-slate-900 dark:hover:text-white' }}" href="{{ route('admin.permission.roles') }}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 shrink-0 transition-colors" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" /></svg>
|
||||||
|
{{ __('Role Settings') }}
|
||||||
|
</a></li>
|
||||||
|
@endcan
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@endrole
|
@endcanany
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,29 @@
|
|||||||
@if ($paginator->hasPages())
|
@if ($paginator->total() > 0)
|
||||||
<div class="flex flex-col sm:flex-row items-center justify-between w-full gap-4">
|
<div class="flex flex-col lg:flex-row items-center justify-between w-full gap-6">
|
||||||
{{-- Total Items Info --}}
|
{{-- Left Side: Limit Selector & Info --}}
|
||||||
<div class="order-2 sm:order-1">
|
<div class="order-2 lg:order-1 flex flex-col sm:flex-row items-center gap-4 sm:gap-6">
|
||||||
<p class="text-[10px] sm:text-[11px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest text-center sm:text-left">
|
{{-- Limit Selector --}}
|
||||||
|
<div class="flex items-center gap-3 bg-slate-50/50 dark:bg-slate-900/50 px-3 py-1.5 rounded-2xl border border-slate-100 dark:border-slate-800 shadow-sm leading-none">
|
||||||
|
<span class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest pl-1 leading-none">{{ __('Show') }}</span>
|
||||||
|
<div class="relative group flex items-center">
|
||||||
|
@php
|
||||||
|
$currentLimit = request('per_page', 10);
|
||||||
|
$limits = [10, 25, 50, 100];
|
||||||
|
@endphp
|
||||||
|
<select onchange="const params = new URLSearchParams(window.location.search); params.set('per_page', this.value); params.delete('page'); window.location.href = window.location.pathname + '?' + params.toString();"
|
||||||
|
class="h-7 pl-2 pr-8 rounded-lg bg-white dark:bg-slate-800 border-none text-[11px] font-black text-slate-600 dark:text-slate-300 appearance-none focus:ring-4 focus:ring-cyan-500/10 outline-none transition-all cursor-pointer shadow-sm leading-none py-0">
|
||||||
|
@foreach($limits as $l)
|
||||||
|
<option value="{{ $l }}" {{ $currentLimit == $l ? 'selected' : '' }}>{{ $l }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
<div class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none opacity-40 group-hover:opacity-100 transition-opacity">
|
||||||
|
<svg class="size-3 text-cyan-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M19 9l-7 7-7-7"/></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Total Items Info --}}
|
||||||
|
<p class="text-[10px] sm:text-[11px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest text-center sm:text-left whitespace-nowrap">
|
||||||
<span class="hidden xs:inline">{{ __('Showing') }}</span>
|
<span class="hidden xs:inline">{{ __('Showing') }}</span>
|
||||||
<span class="text-slate-600 dark:text-slate-300">{{ $paginator->firstItem() }}</span>
|
<span class="text-slate-600 dark:text-slate-300">{{ $paginator->firstItem() }}</span>
|
||||||
{{ __('to') }}
|
{{ __('to') }}
|
||||||
@@ -14,7 +35,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="order-1 sm:order-2 flex items-center gap-x-1.5 sm:gap-x-2">
|
<div class="order-1 lg:order-2 flex items-center gap-x-1.5 sm:gap-x-2">
|
||||||
{{-- Previous Page Link --}}
|
{{-- Previous Page Link --}}
|
||||||
@if ($paginator->onFirstPage())
|
@if ($paginator->onFirstPage())
|
||||||
<span class="h-9 inline-flex items-center gap-x-1.5 sm:gap-x-2 px-3 sm:px-4 rounded-xl text-[10px] sm:text-xs font-black bg-slate-50 dark:bg-slate-800 text-slate-300 dark:text-slate-600 border border-slate-100 dark:border-slate-800 cursor-not-allowed">
|
<span class="h-9 inline-flex items-center gap-x-1.5 sm:gap-x-2 px-3 sm:px-4 rounded-xl text-[10px] sm:text-xs font-black bg-slate-50 dark:bg-slate-800 text-slate-300 dark:text-slate-600 border border-slate-100 dark:border-slate-800 cursor-not-allowed">
|
||||||
@@ -30,7 +51,9 @@
|
|||||||
|
|
||||||
{{-- Unified Quick Jump Selection (Desktop & Mobile) --}}
|
{{-- Unified Quick Jump Selection (Desktop & Mobile) --}}
|
||||||
<div class="relative group">
|
<div class="relative group">
|
||||||
<select onchange="window.location.href = this.value" class="h-9 pl-4 pr-10 rounded-xl bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 text-[11px] sm:text-xs font-black text-slate-600 dark:text-slate-300 appearance-none focus:ring-4 focus:ring-cyan-500/10 focus:border-cyan-500 outline-none transition-all cursor-pointer shadow-sm hover:border-slate-300 dark:hover:border-slate-600">
|
<select onchange="window.location.href = this.value"
|
||||||
|
class="h-9 pl-4 pr-10 rounded-xl bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 text-[11px] sm:text-xs font-black text-slate-600 dark:text-slate-300 appearance-none focus:ring-4 focus:ring-cyan-500/10 focus:border-cyan-500 outline-none transition-all cursor-pointer shadow-sm hover:border-slate-300 dark:hover:border-slate-600 {{ $paginator->lastPage() <= 1 ? 'opacity-50 cursor-not-allowed pointer-events-none' : '' }}"
|
||||||
|
{{ $paginator->lastPage() <= 1 ? 'disabled' : '' }}>
|
||||||
@for ($i = 1; $i <= $paginator->lastPage(); $i++)
|
@for ($i = 1; $i <= $paginator->lastPage(); $i++)
|
||||||
<option value="{{ $paginator->url($i) }}" {{ $i == $paginator->currentPage() ? 'selected' : '' }}>
|
<option value="{{ $paginator->url($i) }}" {{ $i == $paginator->currentPage() ? 'selected' : '' }}>
|
||||||
{{ $i }} / {{ $paginator->lastPage() }}
|
{{ $i }} / {{ $paginator->lastPage() }}
|
||||||
|
|||||||
@@ -165,21 +165,10 @@ Route::middleware(['auth', 'verified', 'tenant.access'])->prefix('admin')->name(
|
|||||||
Route::post('/accounts', [App\Http\Controllers\Admin\PermissionController::class , 'storeAccount'])->name('accounts.store');
|
Route::post('/accounts', [App\Http\Controllers\Admin\PermissionController::class , 'storeAccount'])->name('accounts.store');
|
||||||
Route::put('/accounts/{id}', [App\Http\Controllers\Admin\PermissionController::class , 'updateAccount'])->name('accounts.update');
|
Route::put('/accounts/{id}', [App\Http\Controllers\Admin\PermissionController::class , 'updateAccount'])->name('accounts.update');
|
||||||
Route::delete('/accounts/{id}', [App\Http\Controllers\Admin\PermissionController::class , 'destroyAccount'])->name('accounts.destroy');
|
Route::delete('/accounts/{id}', [App\Http\Controllers\Admin\PermissionController::class , 'destroyAccount'])->name('accounts.destroy');
|
||||||
Route::get('/app-features', [App\Http\Controllers\Admin\PermissionController::class , 'appFeatures'])->name('app-features');
|
|
||||||
Route::get('/data-config', [App\Http\Controllers\Admin\PermissionController::class , 'dataConfig'])->name('data-config');
|
|
||||||
Route::get('/sales', [App\Http\Controllers\Admin\PermissionController::class , 'sales'])->name('sales');
|
|
||||||
Route::get('/machines', [App\Http\Controllers\Admin\PermissionController::class , 'machines'])->name('machines');
|
|
||||||
Route::get('/warehouses', [App\Http\Controllers\Admin\PermissionController::class , 'warehouses'])->name('warehouses');
|
|
||||||
Route::get('/analysis', [App\Http\Controllers\Admin\PermissionController::class , 'analysis'])->name('analysis');
|
|
||||||
Route::get('/audit', [App\Http\Controllers\Admin\PermissionController::class , 'audit'])->name('audit');
|
|
||||||
Route::get('/remote', [App\Http\Controllers\Admin\PermissionController::class , 'remote'])->name('remote');
|
|
||||||
Route::get('/line', [App\Http\Controllers\Admin\PermissionController::class , 'line'])->name('line');
|
|
||||||
Route::get('/roles', [App\Http\Controllers\Admin\PermissionController::class , 'roles'])->name('roles');
|
Route::get('/roles', [App\Http\Controllers\Admin\PermissionController::class , 'roles'])->name('roles');
|
||||||
Route::post('/roles', [App\Http\Controllers\Admin\PermissionController::class , 'storeRole'])->name('roles.store');
|
Route::post('/roles', [App\Http\Controllers\Admin\PermissionController::class , 'storeRole'])->name('roles.store');
|
||||||
Route::put('/roles/{id}', [App\Http\Controllers\Admin\PermissionController::class , 'updateRole'])->name('roles.update');
|
Route::put('/roles/{id}', [App\Http\Controllers\Admin\PermissionController::class , 'updateRole'])->name('roles.update');
|
||||||
Route::delete('/roles/{id}', [App\Http\Controllers\Admin\PermissionController::class , 'destroyRole'])->name('roles.destroy');
|
Route::delete('/roles/{id}', [App\Http\Controllers\Admin\PermissionController::class , 'destroyRole'])->name('roles.destroy');
|
||||||
Route::get('/others', [App\Http\Controllers\Admin\PermissionController::class , 'others'])->name('others');
|
|
||||||
Route::get('/ai-prediction', [App\Http\Controllers\Admin\PermissionController::class , 'aiPrediction'])->name('ai-prediction');
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user