From 1f99664d1984c17f6186e7ee8350deb7f2cca239 Mon Sep 17 00:00:00 2001 From: mirivlad Date: Mon, 30 Mar 2026 12:07:07 +0800 Subject: [PATCH] =?UTF-8?q?Feat:=20Searchable=20Select=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=B3=D1=80=D1=83=D0=BF=D0=BF=20=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✅ TomSelect с мультивыбором (теги как в WordPress) ✅ API /api/groups/search для поиска групп ✅ Обновлён edit.blade.php пользователя ✅ Обновлён show.blade.php пользователя ✅ Компонент поддерживает multiple=true Co-authored-by: Qwen-Coder --- app/Http/Controllers/Admin/UserController.php | 18 +----- .../Controllers/Api/GroupSearchController.php | 30 +++++++++ resources/views/admin/users/edit.blade.php | 14 ++-- resources/views/admin/users/show.blade.php | 64 +++++-------------- .../components/searchable-select.blade.php | 22 ++++--- routes/web.php | 2 + 6 files changed, 71 insertions(+), 79 deletions(-) create mode 100755 app/Http/Controllers/Api/GroupSearchController.php diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index 27314e1..868c49d 100755 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -91,24 +91,8 @@ class UserController extends Controller Gate::authorize('view', $user); $user->load(['organization', 'roles', 'groups']); - - // Получаем доступные группы для пользователя - if ($user->organization_id) { - $availableGroups = Group::whereNull('organization_id') - ->orWhere('organization_id', $user->organization_id) - ->whereDoesntHave('users', function($q) use ($user) { - $q->where('users.id', $user->id); - }) - ->get(); - } else { - $availableGroups = Group::whereNull('organization_id') - ->whereDoesntHave('users', function($q) use ($user) { - $q->where('users.id', $user->id); - }) - ->get(); - } - return view('admin.users.show', compact('user', 'availableGroups')); + return view('admin.users.show', compact('user')); } public function edit(User $user) diff --git a/app/Http/Controllers/Api/GroupSearchController.php b/app/Http/Controllers/Api/GroupSearchController.php new file mode 100755 index 0000000..5cc2131 --- /dev/null +++ b/app/Http/Controllers/Api/GroupSearchController.php @@ -0,0 +1,30 @@ +get('q', ''); + + $groups = Group::query() + ->with('organization') + ->where('name', 'like', "%{$query}%") + ->orderBy('name') + ->limit(50) + ->get() + ->map(function($group) { + return [ + 'id' => $group->id, + 'text' => $group->name . ($group->organization ? " ({$group->organization->name})" : ' (Общая)'), + ]; + }); + + return response()->json($groups); + } +} diff --git a/resources/views/admin/users/edit.blade.php b/resources/views/admin/users/edit.blade.php index c2c7b2d..8db764b 100644 --- a/resources/views/admin/users/edit.blade.php +++ b/resources/views/admin/users/edit.blade.php @@ -63,12 +63,14 @@ @if($allGroups->count() > 0)
- @foreach($allGroups as $group) -
- id, $userGroups) ? 'checked' : '' }}> - -
- @endforeach + + Выберите группы
@endif
diff --git a/resources/views/admin/users/show.blade.php b/resources/views/admin/users/show.blade.php index ddea3f1..ea40cb1 100644 --- a/resources/views/admin/users/show.blade.php +++ b/resources/views/admin/users/show.blade.php @@ -38,24 +38,24 @@
@if($user->groups->count() > 0) -
    - @foreach($user->groups as $group) -
  • -
    - {{ $group->name }} - {{ $group->organization?->name ?? 'Общая группа' }} -
    - @can('update', $group) -
    - @csrf @method('DELETE') - -
    - @endcan -
  • - @endforeach -
+
+ +
@else -

Не состоит в группах

+
+ +
@endif
@@ -64,34 +64,4 @@ - - - @endsection diff --git a/resources/views/components/searchable-select.blade.php b/resources/views/components/searchable-select.blade.php index 42408f5..7ec0d51 100644 --- a/resources/views/components/searchable-select.blade.php +++ b/resources/views/components/searchable-select.blade.php @@ -1,7 +1,7 @@ -@props(['name', 'url', 'placeholder' => 'Начните вводить...', 'value' => null, 'required' => false]) +@props(['name', 'url', 'placeholder' => 'Начните вводить...', 'value' => null, 'required' => false, 'multiple' => false]) - - + + @push('scripts') @@ -15,6 +15,7 @@ document.addEventListener('DOMContentLoaded', function() { placeholder: '{{ $placeholder }}', preload: false, maxOptions: null, + {{ $multiple ? 'persist: false, hideSelected: true,' : '' }} load: function(query, callback) { if (query.length < 2) return callback(); @@ -35,7 +36,7 @@ document.addEventListener('DOMContentLoaded', function() { } }, onChange: function(value) { - document.getElementById('{{ $name }}').value = value; + document.getElementById('{{ $name }}').value = {{ $multiple ? 'Array.isArray(value) ? value.join(",") : value' : 'value' }}; } }); @@ -43,11 +44,14 @@ document.addEventListener('DOMContentLoaded', function() { fetch('{{ $url }}?q=') .then(response => response.json()) .then(items => { - const item = items.find(i => i.id == '{{ $value }}'); - if (item) { - select.addOption(item); - select.setValue('{{ $value }}'); - } + const values = {{ is_array($value) ? json_encode($value) : "['" . $value . "']" }}; + values.forEach(val => { + const item = items.find(i => i.id == val); + if (item) { + select.addOption(item); + } + }); + select.setValue(values); }); @endif }); diff --git a/routes/web.php b/routes/web.php index a601f42..f8d8360 100644 --- a/routes/web.php +++ b/routes/web.php @@ -12,6 +12,7 @@ use App\Http\Controllers\Admin\QuestionController; use App\Http\Controllers\Admin\CourseAssignmentController; use App\Http\Controllers\Admin\GroupUserController; use App\Http\Controllers\Api\OrganizationSearchController; +use App\Http\Controllers\Api\GroupSearchController; use App\Http\Controllers\DashboardController; use Illuminate\Support\Facades\Route; @@ -58,5 +59,6 @@ Route::middleware('auth')->group(function () { // API для поиска (требуется аутентификация) Route::middleware('auth')->group(function() { Route::get('/api/organizations/search', OrganizationSearchController::class)->name('api.organizations.search'); + Route::get('/api/groups/search', GroupSearchController::class)->name('api.groups.search'); }); });