feat(projects): Plan 5 Task 2 — index expanded (filters/search/pagination/ids) + show
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,48 +5,79 @@ declare(strict_types=1);
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\ProjectResource;
|
||||
use App\Models\Project;
|
||||
use App\Models\Tenant;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* Проекты tenant'а — для NewDealDialog dropdown'а и DealsView/Smart-filters.
|
||||
* Проекты tenant'а — расширенный API для ProjectsView + NewDealDialog.
|
||||
*
|
||||
* На MVP: tenant_id параметром. На prod: middleware('auth:sanctum')+'tenant'.
|
||||
* index: фильтры по signal_type/status/search, пагинация, batch-fetch по ids.
|
||||
* show: детальная карточка проекта с supplier_links.
|
||||
*
|
||||
* Auth: auth:sanctum + tenant middleware (устанавливает app.current_tenant_id для RLS).
|
||||
* Task 2 Plan 5 заменяет MVP-версию (tenant_id параметром, без auth).
|
||||
*/
|
||||
class ProjectController extends Controller
|
||||
{
|
||||
/** GET /api/projects?tenant_id={id} */
|
||||
/** GET /api/projects */
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$tenantId = (int) $request->query('tenant_id', '0');
|
||||
if ($tenantId < 1) {
|
||||
return response()->json(['message' => 'Параметр tenant_id обязателен.'], 422);
|
||||
$query = Project::query()->where('tenant_id', $request->user()->tenant_id);
|
||||
|
||||
// Batch-fetch по ids — возвращает без пагинации (для dropdown'ов и т.п.)
|
||||
if ($ids = $request->query('ids')) {
|
||||
$idArray = array_filter(array_map('intval', explode(',', (string) $ids)));
|
||||
$items = $query->whereIn('id', $idArray)->get();
|
||||
|
||||
return response()->json(['data' => ProjectResource::collection($items)]);
|
||||
}
|
||||
|
||||
$tenant = Tenant::find($tenantId);
|
||||
if ($tenant === null) {
|
||||
return response()->json(['message' => 'Тенант не найден.'], 404);
|
||||
// Фильтр по типу сигнала
|
||||
if ($type = $request->query('signal_type')) {
|
||||
$query->where('signal_type', $type);
|
||||
}
|
||||
|
||||
$projects = DB::transaction(function () use ($tenantId) {
|
||||
DB::statement('SET LOCAL app.current_tenant_id = '.$tenantId);
|
||||
// Фильтр по статусу жизненного цикла
|
||||
$status = $request->query('status');
|
||||
if ($status === 'archived') {
|
||||
$query->archived();
|
||||
} elseif ($status === 'active') {
|
||||
$query->active()->where('is_active', true);
|
||||
} elseif ($status === 'paused') {
|
||||
$query->active()->where('is_active', false);
|
||||
} else {
|
||||
// По умолчанию: все не архивированные (active + paused)
|
||||
$query->active();
|
||||
}
|
||||
|
||||
return Project::query()
|
||||
->where('is_active', true)
|
||||
->orderBy('name')
|
||||
->get(['id', 'name', 'tag', 'type']);
|
||||
});
|
||||
// Поиск по name и signal_identifier
|
||||
if ($search = $request->query('search')) {
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('name', 'ilike', "%{$search}%")
|
||||
->orWhere('signal_identifier', 'ilike', "%{$search}%");
|
||||
});
|
||||
}
|
||||
|
||||
$perPage = min((int) $request->query('per_page', '20'), 100);
|
||||
$projects = $query->orderBy('created_at', 'desc')->paginate($perPage);
|
||||
|
||||
return response()->json([
|
||||
'projects' => $projects->map(fn (Project $p) => [
|
||||
'id' => $p->id,
|
||||
'name' => $p->name,
|
||||
'tag' => $p->tag,
|
||||
'type' => $p->type,
|
||||
]),
|
||||
'data' => ProjectResource::collection($projects->items()),
|
||||
'meta' => [
|
||||
'current_page' => $projects->currentPage(),
|
||||
'per_page' => $projects->perPage(),
|
||||
'total' => $projects->total(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/** GET /api/projects/{id} */
|
||||
public function show(Request $request, int $id): JsonResponse
|
||||
{
|
||||
$project = Project::where('tenant_id', $request->user()->tenant_id)->findOrFail($id);
|
||||
|
||||
return response()->json(['data' => new ProjectResource($project)]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user