input('per_page', 10); $user = auth()->user(); $query = \App\Models\System\Role::query()->with(['permissions', 'users']); // 租戶隔離:租戶只能看到自己公司的角色 + 系統角色 (company_id is null) if (!$user->isSystemAdmin()) { $query->where('company_id', $user->company_id); } // 搜尋:角色名稱 if ($search = request()->input('search')) { $query->where('name', 'like', "%{$search}%"); } $roles = $query->latest()->paginate($per_page)->withQueryString(); $all_permissions = \Spatie\Permission\Models\Permission::all() ->filter(function($perm) { // 排除子項目的權限,只顯示主選單權限 $excluded = [ 'menu.basic.machines', 'menu.basic.payment-configs', 'menu.companies', 'menu.accounts', 'menu.roles', ]; return !in_array($perm->name, $excluded); }) ->groupBy(function($perm) { if (str_starts_with($perm->name, 'menu.')) { return 'menu'; } return 'other'; }); // 根據路由決定標題 $title = request()->routeIs('*.sub-account-roles') ? __('Sub Account Roles') : __('Role Settings'); return view('admin.permission.roles', compact('roles', 'all_permissions', 'title')); } /** * Store a newly created role in storage. */ public function storeRole(Request $request) { $is_system = auth()->user()->isSystemAdmin() && $request->boolean('is_system'); $company_id = $is_system ? null : auth()->user()->company_id; $validated = $request->validate([ 'name' => [ 'required', 'string', 'max:255', \Illuminate\Validation\Rule::unique('roles', 'name')->where(function ($query) use ($company_id) { return $query->where('company_id', $company_id); }) ], 'permissions' => 'nullable|array', 'permissions.*' => 'string|exists:permissions,name', ]); $role = \App\Models\System\Role::query()->create([ 'name' => $validated['name'], 'guard_name' => 'web', 'company_id' => $is_system ? null : auth()->user()->company_id, 'is_system' => $is_system, ]); if (!empty($validated['permissions'])) { $perms = $validated['permissions']; // 如果不是系統角色,排除主選單的系統權限 if (!$is_system) { $perms = array_diff($perms, ['menu.basic-settings', 'menu.permissions']); } $role->syncPermissions($perms); } return redirect()->back()->with('success', __('Role created successfully.')); } /** * Update the specified role in storage. */ public function updateRole(Request $request, $id) { $role = \App\Models\System\Role::findOrFail($id); $is_system = $role->is_system; $company_id = $role->company_id; $validated = $request->validate([ 'name' => [ 'required', 'string', 'max:255', \Illuminate\Validation\Rule::unique('roles', 'name') ->ignore($id) ->where(function ($query) use ($company_id) { return $query->where('company_id', $company_id); }) ], 'permissions' => 'nullable|array', 'permissions.*' => 'string|exists:permissions,name', ]); if ($role->name === 'super-admin') { return redirect()->back()->with('error', __('The Super Admin role is immutable.')); } if (!auth()->user()->isSystemAdmin() && $role->is_system) { return redirect()->back()->with('error', __('System roles cannot be modified by tenant administrators.')); } $is_system = auth()->user()->isSystemAdmin() ? $request->boolean('is_system') : $role->is_system; $role->update([ 'name' => $validated['name'], 'is_system' => $is_system, 'company_id' => $is_system ? null : $role->company_id, ]); $perms = $validated['permissions'] ?? []; // 如果不是系統角色,排除主選單的系統權限 if (!$is_system) { $perms = array_diff($perms, ['menu.basic-settings', 'menu.permissions']); } $role->syncPermissions($perms); return redirect()->back()->with('success', __('Role updated successfully.')); } /** * Remove the specified role from storage. */ public function destroyRole($id) { $role = \App\Models\System\Role::findOrFail($id); if ($role->name === 'super-admin') { return redirect()->back()->with('error', __('The Super Admin role cannot be deleted.')); } if (!auth()->user()->isSystemAdmin() && $role->is_system) { return redirect()->back()->with('error', __('System roles cannot be deleted by tenant administrators.')); } if ($role->users()->count() > 0) { return redirect()->back()->with('error', __('Cannot delete role with active users.')); } $role->delete(); return redirect()->back()->with('success', __('Role deleted successfully.')); } // 帳號管理 public function accounts(Request $request) { $query = \App\Models\System\User::query()->with(['company', 'roles']); // 租戶隔離:如果不是系統管理員,則只看自己公司的成員 if (!auth()->user()->isSystemAdmin()) { $query->where('company_id', auth()->user()->company_id); } // 搜尋 if ($search = $request->input('search')) { $query->where(function($q) use ($search) { $q->where('name', 'like', "%{$search}%") ->orWhere('username', 'like', "%{$search}%") ->orWhere('email', 'like', "%{$search}%"); }); } // 公司篩選 (僅限 super-admin) if (auth()->user()->isSystemAdmin() && $request->filled('company_id')) { $query->where('company_id', $request->company_id); } $per_page = $request->input('per_page', 10); $users = $query->latest()->paginate($per_page)->withQueryString(); $companies = auth()->user()->isSystemAdmin() ? \App\Models\System\Company::all() : collect(); $roles_query = \App\Models\System\Role::where('name', '!=', 'super-admin'); if (!auth()->user()->isSystemAdmin()) { $roles_query->where('company_id', auth()->user()->company_id); } $roles = $roles_query->get(); // 根據路由決定標題 $title = request()->routeIs('*.sub-accounts') ? __('Sub Account Management') : __('Account Management'); return view('admin.data-config.accounts', compact('users', 'companies', 'roles', 'title')); } /** * Store a newly created account in storage. */ public function storeAccount(Request $request) { $validated = $request->validate([ 'name' => 'required|string|max:255', 'username' => 'required|string|max:255|unique:users,username', 'email' => 'required|email|max:255|unique:users,email', 'password' => 'required|string|min:8', 'role' => 'required|string', 'status' => 'required|boolean', 'company_id' => 'nullable|exists:companies,id', 'phone' => 'nullable|string|max:20', ]); $company_id = auth()->user()->isSystemAdmin() ? ($validated['company_id'] ?? null) : auth()->user()->company_id; // 查找角色:優先尋找該公司的角色,若無則尋找全域範本 $role = \App\Models\System\Role::where('name', $validated['role']) ->where(function($q) use ($company_id) { $q->where('company_id', $company_id)->orWhereNull('company_id'); }) ->first(); if (!$role) { return redirect()->back()->with('error', __('Role not found.')); } // 驗證角色與公司的匹配性 (RBAC Safeguard) if ($company_id !== null) { // 如果是租戶帳號,不能選各項系統角色 (is_system = 1) if ($role->is_system) { return redirect()->back()->with('error', __('System roles cannot be assigned to tenant accounts.')); } // 如果角色有特定的 company_id,必須匹配 if ($role->company_id !== null && $role->company_id != $company_id) { return redirect()->back()->with('error', __('This role belongs to another company and cannot be assigned.')); } } else { // 如果是系統層級帳號,只能選系統角色 (is_system = 1) if (!$role->is_system) { return redirect()->back()->with('error', __('Only system roles can be assigned to platform administrative accounts.')); } } // 角色初始化與克隆邏輯 (只有 super-admin 在幫空白公司開帳號時觸發) $role_to_assign = $validated['role']; $company_id = auth()->user()->isSystemAdmin() ? ($validated['company_id'] ?? null) : auth()->user()->company_id; if ($company_id && $role && !$role->is_system && $role->company_id === null) { // 檢查該公司是否已有名為「管理員」的角色 $existingRole = \App\Models\System\Role::where('company_id', $company_id) ->where('name', '管理員') ->first(); if (!$existingRole) { // 克隆範本為該公司的「管理員」 $clonedRole = \App\Models\System\Role::query()->create([ 'name' => '管理員', 'guard_name' => 'web', 'company_id' => $company_id, 'is_system' => false, ]); $clonedRole->syncPermissions($role->permissions); $role_to_assign = '管理員'; } else { // 如果已存在名為「管理員」的角色,則直接使用它 $role_to_assign = '管理員'; } } $user = \App\Models\System\User::create([ 'name' => $validated['name'], 'username' => $validated['username'], 'email' => $validated['email'], 'password' => \Illuminate\Support\Facades\Hash::make($validated['password']), 'status' => $validated['status'], 'company_id' => $company_id, 'phone' => $validated['phone'], ]); $user->assignRole($role_to_assign); return redirect()->back()->with('success', __('Account created successfully.')); } /** * Update the specified account in storage. */ public function updateAccount(Request $request, $id) { $user = \App\Models\System\User::findOrFail($id); if ($user->hasRole('super-admin')) { return redirect()->back()->with('error', __('System super admin accounts cannot be modified via this interface.')); } $validated = $request->validate([ 'name' => 'required|string|max:255', 'username' => 'required|string|max:255|unique:users,username,' . $id, 'email' => 'required|email|max:255|unique:users,email,' . $id, 'password' => 'nullable|string|min:8', 'role' => 'required|string', 'status' => 'required|boolean', 'company_id' => 'nullable|exists:companies,id', 'phone' => 'nullable|string|max:20', ]); $target_company_id = auth()->user()->isSystemAdmin() ? ($validated['company_id'] ?? null) : auth()->user()->company_id; // 查找角色:優先尋找該公司的角色,若無則尋找全域範本 $roleObj = \App\Models\System\Role::where('name', $validated['role']) ->where(function($q) use ($target_company_id) { $q->where('company_id', $target_company_id)->orWhereNull('company_id'); }) ->first(); if (!$roleObj) { return redirect()->back()->with('error', __('Role not found.')); } // 驗證角色與公司的匹配性 (RBAC Safeguard) if ($user->id !== auth()->id()) { // 排除編輯自己 (super-admin 有特殊邏輯) if ($target_company_id !== null) { if ($roleObj->is_system) { return redirect()->back()->with('error', __('System roles cannot be assigned to tenant accounts.')); } if ($roleObj->company_id !== null && $roleObj->company_id != $target_company_id) { return redirect()->back()->with('error', __('This role belongs to another company and cannot be assigned.')); } } else { if (!$roleObj->is_system) { return redirect()->back()->with('error', __('Only system roles can be assigned to platform administrative accounts.')); } } } $updateData = [ 'name' => $validated['name'], 'username' => $validated['username'], 'email' => $validated['email'], 'status' => $validated['status'], 'phone' => $validated['phone'], ]; if (auth()->user()->isSystemAdmin()) { // 防止超級管理員不小心把自己綁定到租客公司或降級 if ($user->id === auth()->id()) { $updateData['company_id'] = null; $validated['role'] = 'super-admin'; } else { $updateData['company_id'] = $validated['company_id']; } } if (!empty($validated['password'])) { $updateData['password'] = \Illuminate\Support\Facades\Hash::make($validated['password']); } // 角色初始化與克隆邏輯 $role_to_assign = $validated['role']; $target_company_id = auth()->user()->isSystemAdmin() ? ($validated['company_id'] ?? null) : auth()->user()->company_id; if ($target_company_id && $roleObj && !$roleObj->is_system && $roleObj->company_id === null) { // 檢查該公司是否已有名為「管理員」的角色 $existingRole = \App\Models\System\Role::where('company_id', $target_company_id) ->where('name', '管理員') ->first(); if (!$existingRole) { $clonedRole = \App\Models\System\Role::query()->create([ 'name' => '管理員', 'guard_name' => 'web', 'company_id' => $target_company_id, 'is_system' => false, ]); $clonedRole->syncPermissions($roleObj->permissions); $role_to_assign = '管理員'; } else { $role_to_assign = '管理員'; } } $user->update($updateData); // 如果是編輯自己且原本是超級管理員,強制保留 super-admin 角色 if ($user->id === auth()->id() && auth()->user()->isSystemAdmin()) { $user->syncRoles(['super-admin']); } else { $user->syncRoles([$role_to_assign]); } return redirect()->back()->with('success', __('Account updated successfully.')); } /** * Remove the specified account from storage. */ public function destroyAccount($id) { $user = \App\Models\System\User::findOrFail($id); if ($user->hasRole('super-admin')) { return redirect()->back()->with('error', __('System super admin accounts cannot be deleted.')); } if ($user->id === auth()->id()) { return redirect()->back()->with('error', __('You cannot delete your own account.')); } // 為了解決軟刪除導致的唯一索引佔用問題,刪除前先重命名唯一欄位 $timestamp = now()->getTimestamp(); $user->username = $user->username . '.deleted.' . $timestamp; $user->email = $user->email . '.deleted.' . $timestamp; $user->save(); $user->delete(); return redirect()->back()->with('success', __('Account deleted successfully.')); } }