доработка функционала регионального менеджера

This commit is contained in:
Thekindbull 2025-11-22 21:12:31 +08:00
parent 75b587131f
commit f28f58b742
15 changed files with 268 additions and 69 deletions

View File

@ -40,7 +40,7 @@ class Kernel extends HttpKernel
'api' => [ 'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api', \Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class, \Illuminate\Routing\Middleware\SubstituteBindings::class,
], ],
]; ];
@ -53,16 +53,16 @@ class Kernel extends HttpKernel
* @var array<string, class-string|string> * @var array<string, class-string|string>
*/ */
protected $middlewareAliases = [ protected $middlewareAliases = [
'auth' => \App\Http\Middleware\Authenticate::class, 'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class, 'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class, 'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
'signed' => \App\Http\Middleware\ValidateSignature::class, 'signed' => \App\Http\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
]; ];
} }

View File

@ -2,18 +2,24 @@
namespace Modules\Admin\Http\Controllers; namespace Modules\Admin\Http\Controllers;
use Illuminate\Http\Request;
use Modules\Main\Models\City;
use Modules\Post\Models\Post; use Modules\Post\Models\Post;
use Modules\Post\Models\PostCategory;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Illuminate\Http\Request; use Modules\Post\Models\PostCategory;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
class AdminPostsController extends Controller class AdminPostsController extends Controller
{ {
public function index() public function index()
{ {
$posts = Post::orderBy('id', 'desc')->get(); $posts = Post::orderBy('id', 'desc');
if (!auth()->user()->isAdmin() && auth()->user()->isCityManager())
{
}
$posts = $posts->get();
return view('admin::posts.index', [ return view('admin::posts.index', [
'posts' => $posts 'posts' => $posts
]); ]);
@ -40,6 +46,15 @@ public function store(Request $request)
$post = Post::create( $post = Post::create(
$request->only(['name', 'short_text', 'text', 'category', 'image']) $request->only(['name', 'short_text', 'text', 'category', 'image'])
); );
if (array_key_exists('cities', $request->all()) && is_array($request['cities']))
{
foreach ($request->cities as $cityId)
{
$post->cities()->create([
'city_id' => $cityId,
]);
}
}
return to_route('admin.posts'); return to_route('admin.posts');
} }

View File

@ -1,53 +1,44 @@
<div> <div>
@if (in_array($roles::SUPER_ADMIN, $userRoles)) <ul class="nav flex flex-md-column">
<ul class="nav flex flex-md-column"> <li class="d-none d-md-block">
<li class="d-none d-md-block"> <h6 class="dropdown-header text-uppercase">Основное</h6>
<h6 class="dropdown-header text-uppercase">Основное</h6> </li>
</li> <li class="nav-item text-center m-2"><a class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4"
<li class="nav-item text-center m-2"><a class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4" href="{{ route('admin.posts') }}">Новости</a>
href="{{ route('admin.posts') }}">Новости</a> </li>
</li> <li class="nav-item text-center m-2 d-none"><a
<li class="nav-item text-center m-2 d-none"><a class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4" href="#">Объекты</a></li>
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4" href="#">Объекты</a></li> <li class="nav-item text-center m-2"><a class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4"
<li class="nav-item text-center m-2"><a href="{{ route('admin.users') }}">Пользователи</a>
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4" </li>
href="{{ route('admin.users') }}">Пользователи</a> <li>
</li> <h6 class="dropdown-header text-uppercase">Справочники</h6>
<li> </li>
<h6 class="dropdown-header text-uppercase">Справочники</h6> <li class="nav-item text-center m-2"><a class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4"
</li> href="{{ route('admin.cities', ['filter' => 'actual']) }}">Города</a></li>
<li class="nav-item text-center m-2"><a <li class="nav-item text-center m-2"><a class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4"
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4" href="{{ route('admin.complexes', ['filter' => 'actual']) }}">ЖК</a>
href="{{ route('admin.cities', ['filter' => 'actual']) }}">Города</a></li> </li>
<li class="nav-item text-center m-2"><a <li class="nav-item text-center m-2"><a class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4"
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4" href="{{ route('admin.cities.managers') }}">Менеджеры</a>
href="{{ route('admin.complexes', ['filter' => 'actual']) }}">ЖК</a> </li>
</li> <li>
<li class="nav-item text-center m-2"><a <h6 class="dropdown-header text-uppercase">Агентства</h6>
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4" </li>
href="{{ route('admin.cities.managers') }}">Менеджеры</a> <li class="nav-item text-center m-2"><a class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4"
</li> href="{{ route('admin.companies') }}">Организации</a></li>
<li> <li class="nav-item text-center m-2"><a class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4"
<h6 class="dropdown-header text-uppercase">Агентства</h6> href="{{ route('admin.payments') }}">Вознаграждения</a></li>
</li> <li>
<li class="nav-item text-center m-2"><a <h6 class="dropdown-header text-uppercase">Прочее</h6>
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4" </li>
href="{{ route('admin.companies') }}">Организации</a></li> <li class="nav-item text-center m-2"><a class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4"
<li class="nav-item text-center m-2"><a href="{{ route('admin.docs') }}">Документы</a></li>
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4" <li>
href="{{ route('admin.payments') }}">Вознаграждения</a></li> <h6 class="dropdown-header text-uppercase">Интеграции</h6>
<li> </li>
<h6 class="dropdown-header text-uppercase">Прочее</h6> <li class="nav-item text-center m-2"><a class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4"
</li> href="{{ route('admin.bitrix') }}">Битрикс24</a></li>
<li class="nav-item text-center m-2"><a </ul>
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4"
href="{{ route('admin.docs') }}">Документы</a></li>
<li>
<h6 class="dropdown-header text-uppercase">Интеграции</h6>
</li>
<li class="nav-item text-center m-2"><a
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4"
href="{{ route('admin.bitrix') }}">Битрикс24</a></li>
</ul>
@endif
</div> </div>

View File

@ -49,6 +49,7 @@
<div class="text-danger">{{ $message }}</div> <div class="text-danger">{{ $message }}</div>
@enderror @enderror
</div> </div>
<input type="text" name="cities[0]" value="1" />
<button type="submit" class="btn btn-primary">Сохранить</button> <button type="submit" class="btn btn-primary">Сохранить</button>
</form> </form>
@endsection @endsection

View File

@ -17,6 +17,7 @@
<tr scope="row"> <tr scope="row">
<td class="align-middle"> <td class="align-middle">
{{ $post->name }} {{ $post->name }}
<br>{{ $post->city }}
</td> </td>
<td> <td>
{{ $post->created_at->diffForHumans() }} {{ $post->created_at->diffForHumans() }}

View File

@ -81,6 +81,7 @@ protected static function booted()
} }
throw new \Exception('Error of bitrix identifier getter for ' . $bitrixId->bitrixable_type . ' with id ' . $bitrixId->bitrixable_id); throw new \Exception('Error of bitrix identifier getter for ' . $bitrixId->bitrixable_type . ' with id ' . $bitrixId->bitrixable_id);
}); });
static::created(function (BitrixId $bitrixId) static::created(function (BitrixId $bitrixId)
{ {
if (!$bitrixId->bx_id) if (!$bitrixId->bx_id)

View File

@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('city_appends', function (Blueprint $table)
{
$table->id();
$table->morphs('append');
$table->foreignId('city_id')->references('id')->on('cities')->onDelete('cascade');
$table->text('data')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('client_contract');
}
};

View File

@ -1,7 +1,9 @@
<?php <?php
use Modules\Contracts\Models\ContractStatus; use Modules\Contracts\Models\ContractStatus;
use Modules\Main\Models\Company\Company;
use Modules\Main\Models\Company\CompanyAdmin; use Modules\Main\Models\Company\CompanyAdmin;
use Modules\CityManager\Models\CityManager;
use Modules\Main\Models\Agent\Agent; use Modules\Main\Models\Agent\Agent;
use Modules\Main\Models\Complex; use Modules\Main\Models\Complex;
@ -47,9 +49,16 @@ function GetAvailableAgents()
} }
else else
{ {
$agents = Agent::where('user_id', auth()->user()->id); $cityManager = CityManager::where('user_id', auth()->user()->id);
if ($cityManager->count())
{
$agents = Agent::whereIn('company_id', Company::where('city_id', $cityManager->city_id)->get()->pluck('company_id'));
}
else
{
$agents = Agent::where('user_id', auth()->user()->id);
}
} }
$agents->with('company:id,name'); $agents->with('company:id,name');
$agents->with('user:id,name'); $agents->with('user:id,name');
return $agents->get()->toArray(); return $agents->get()->toArray();
@ -78,4 +87,31 @@ function GetAvailableComplexes()
} }
return []; return [];
} }
}
if (!function_exists('GetAvailableCities'))
{
function GetAvailableAgents()
{
$agents = [];
if ($adminCompany = AdminCompanyOfUser())
{
$agents = Agent::where('company_id', $adminCompany->id);
}
else
{
$cityManager = CityManager::where('user_id', auth()->user()->id);
if ($cityManager->count())
{
$agents = Agent::whereIn('company_id', Company::where('city_id', $cityManager->city_id)->get()->pluck('company_id'));
}
else
{
$agents = Agent::where('user_id', auth()->user()->id);
}
}
$agents->with('company:id,name');
$agents->with('user:id,name');
return $agents->get()->toArray();
}
} }

View File

@ -0,0 +1,22 @@
<?php
namespace Modules\Main\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class CityAppend extends Model
{
use HasFactory;
protected $fillable = [
'city_id',
'data'
];
public function object(): MorphTo
{
return $this->morphTo();
}
}

View File

@ -19,13 +19,14 @@ public function register()
public function boot() public function boot()
{ {
$this->registerPolicies();
$this->registerViews(); $this->registerViews();
$this->registerLivewireViews(); $this->registerLivewireViews();
$this->registerMigrations(); $this->registerMigrations();
$this->registerConfig(); $this->registerConfig();
$this->registerComponent(); $this->registerComponent();
$this->registerLivewire(); $this->registerLivewire();
$this->registerPolicies(); $this->registerHelpers();
} }
protected function registerViews() protected function registerViews()
@ -77,4 +78,13 @@ protected function registerPolicies()
{ {
Gate::policy(\Modules\Main\Models\Company\Company::class, \Modules\Main\Http\Policies\CompanyPolicy::class); Gate::policy(\Modules\Main\Models\Company\Company::class, \Modules\Main\Http\Policies\CompanyPolicy::class);
} }
protected function registerHelpers()
{
$files = glob(__DIR__ . '/../Helpers/' . "*.php");
foreach ($files as $key => $file)
{
require_once $file;
}
}
} }

View File

@ -0,0 +1,23 @@
<?php
namespace Modules\Main\Traits;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Modules\Main\Models\CityAppend;
trait CityAppendTrait
{
public function cities(): MorphMany
{
return $this->MorphMany(CityAppend::class, 'append');
}
public function byCity(Builder $query, $cityId)
{
//return $query->where('category', $category);
}
}

View File

@ -2,11 +2,17 @@
namespace Modules\Post\Models; namespace Modules\Post\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Modules\Main\Models\City;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Modules\Main\Traits\CityAppendTrait;
class Post extends Model class Post extends Model
{ {
use HasFactory; use HasFactory;
use CityAppendTrait;
protected $fillable = [ protected $fillable = [
'name', 'name',

View File

@ -57,6 +57,30 @@ public function getPartialsName()
'familyName' => (array_key_exists(2, $name) ? $name[2] : '') 'familyName' => (array_key_exists(2, $name) ? $name[2] : '')
]; ];
} }
/**
* Функция проверят наличие роли у пользователя
* @param mixed $roleId - лучше брать из констант модели Modules\User\Models\Role
* @return bool
*/
public function hasRole($roleId)
{
$roles = $this->roles()->get();
if ($roles->where('id', $roleId)->count())
{
return true;
}
return false;
}
public function isAdmin()
{
return $this->hasRole(Role::SUPER_ADMIN);
}
public function isCityManager()
{
return $this->hasRole(Role::CITY_MANAGER);
}
public function roles(): HasManyThrough public function roles(): HasManyThrough
{ {
@ -75,4 +99,5 @@ public function roles(): HasManyThrough
); );
} }
} }

View File

@ -0,0 +1,36 @@
<?php
namespace Modules\User\Providers;
use Illuminate\Support\Facades\Blade;
use Livewire\Livewire;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Auth;
use Modules\User\Models\UserRole;
use Modules\User\Models\Role;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
public function boot()
{
Gate::define('admin', function ($user)
{
if (!Auth::check())
{
abort(403, 'Unauthorized action');
}
$user = Auth::user();
if (
!UserRole::where('user_id', $user->id)
->where('role_id', Role::SUPER_ADMIN)->count()
)
{
abort(403, 'Unauthorized action');
}
return true;
});
}
}

View File

@ -12,6 +12,7 @@ class ModuleServiceProvider extends ServiceProvider
public function register() public function register()
{ {
$this->app->register(AuthServiceProvider::class);
$this->app->register(RouteServiceProvider::class); $this->app->register(RouteServiceProvider::class);
} }