1. [FEAT] 權限劃分為「系統層級」與「客戶層級」,並在後端強制過濾跨權限分配。 2. [FEAT] 整合選單權限至主選單層級 (基本設定、權限設定),簡化角色管理 UI。 3. [STYLE] 側邊欄優化:補齊多語系翻譯,並為基本設定子選單增加視覺圖示。 4. [REFACTOR] 更新 RoleSeeder,將 tenant-admin 重新分類為客戶層級角色。
300 lines
11 KiB
PHP
300 lines
11 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use Illuminate\Http\Request;
|
|
|
|
class PermissionController extends Controller
|
|
{
|
|
// 權限角色設定
|
|
public function roles()
|
|
{
|
|
$per_page = request()->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(function($q) use ($user) {
|
|
$q->where('company_id', $user->company_id)
|
|
->orWhereNull('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)
|
|
{
|
|
$validated = $request->validate([
|
|
'name' => 'required|string|max:255|unique:roles,name',
|
|
'permissions' => 'nullable|array',
|
|
'permissions.*' => 'string|exists:permissions,name',
|
|
]);
|
|
|
|
$is_system = auth()->user()->isSystemAdmin() && $request->boolean('is_system');
|
|
|
|
$role = \App\Models\System\Role::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);
|
|
|
|
$validated = $request->validate([
|
|
'name' => 'required|string|max:255|unique:roles,name,' . $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(function($q) {
|
|
$q->where('company_id', auth()->user()->company_id)
|
|
->orWhereNull('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' => 'nullable|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',
|
|
]);
|
|
|
|
$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' => auth()->user()->isSystemAdmin() ? $validated['company_id'] : auth()->user()->company_id,
|
|
'phone' => $validated['phone'],
|
|
]);
|
|
|
|
$user->assignRole($validated['role']);
|
|
|
|
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' => 'nullable|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',
|
|
]);
|
|
|
|
$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']);
|
|
}
|
|
|
|
$user->update($updateData);
|
|
|
|
// 如果是編輯自己且原本是超級管理員,強制保留 super-admin 角色
|
|
if ($user->id === auth()->id() && auth()->user()->isSystemAdmin()) {
|
|
$user->syncRoles(['super-admin']);
|
|
} else {
|
|
$user->syncRoles([$validated['role']]);
|
|
}
|
|
|
|
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.'));
|
|
}
|
|
|
|
$user->delete();
|
|
|
|
return redirect()->back()->with('success', __('Account deleted successfully.'));
|
|
}
|
|
}
|