diff --git a/app/Http/Controllers/Api/Admin/AuthController.php b/app/Http/Controllers/Api/Admin/AuthController.php index 35180e8..7ff1a9c 100644 --- a/app/Http/Controllers/Api/Admin/AuthController.php +++ b/app/Http/Controllers/Api/Admin/AuthController.php @@ -8,7 +8,6 @@ use App\Http\Controllers\Controller; use App\Models\Admin; use App\Services\LogService; -use App\Traits\ApiResponse; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; @@ -18,26 +17,33 @@ class AuthController extends Controller { - use ApiResponse; + /** + * @var LogService + */ + private readonly LogService $logService; - public function __construct( - private readonly LogService $logService, - ) {} + public function __construct(LogService $logService) + { + $this->logService = $logService; + } /** * 管理员登录 * * @param Request $request * @return JsonResponse + * @throws ValidationException */ public function login(Request $request): JsonResponse { try { + /** @var array{email: string, password: string} $validated */ $validated = $request->validate([ 'email' => 'required|email', 'password' => 'required|string', ]); + /** @var Admin|null $admin */ $admin = Admin::where('email', $validated['email'])->first(); if (!$admin || !Hash::check($validated['password'], $admin->password)) { @@ -47,6 +53,7 @@ public function login(Request $request): JsonResponse ); } + /** @var string $token */ $token = $admin->createToken('admin-token')->plainTextToken; $this->logService->logOperation( @@ -59,7 +66,6 @@ public function login(Request $request): JsonResponse 'token' => $token, 'admin' => [ 'id' => $admin->id, - 'name' => $admin->name, 'email' => $admin->email, ], ]); @@ -92,7 +98,16 @@ public function login(Request $request): JsonResponse public function logout(Request $request): JsonResponse { try { + /** @var Admin|null $admin */ $admin = $request->user(); + + if (!$admin) { + return $this->error( + ErrorCode::UNAUTHORIZED, + '未登錄或會話已過期。' + ); + } + $admin->currentAccessToken()->delete(); $this->logService->logOperation( @@ -122,17 +137,27 @@ public function logout(Request $request): JsonResponse * * @param Request $request * @return JsonResponse + * @throws ValidationException */ public function changePassword(Request $request): JsonResponse { try { + /** @var Admin|null $admin */ + $admin = $request->user(); + + if (!$admin) { + return $this->error( + ErrorCode::UNAUTHORIZED, + '未登錄或會話已過期。' + ); + } + + /** @var array{current_password: string, new_password: string} $validated */ $validated = $request->validate([ 'current_password' => 'required|string', 'new_password' => 'required|string|min:8|confirmed', ]); - $admin = $request->user(); - if (!Hash::check($validated['current_password'], $admin->password)) { return $this->error( ErrorCode::INVALID_CREDENTIALS, diff --git a/app/Http/Controllers/Api/Admin/ClientController.php b/app/Http/Controllers/Api/Admin/ClientController.php index 6642266..fc36955 100644 --- a/app/Http/Controllers/Api/Admin/ClientController.php +++ b/app/Http/Controllers/Api/Admin/ClientController.php @@ -8,28 +8,31 @@ use App\Http\Controllers\Controller; use App\Models\Admin; use App\Models\Client; +use App\Models\LlmProvider; use App\Services\Auth\TokenService; -use App\Services\LogService; -use App\Traits\ApiResponse; -use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; -use Illuminate\Support\Facades\Redis; use Illuminate\Validation\ValidationException; class ClientController extends Controller { - use ApiResponse; - - private Admin $admin; + /** + * @var TokenService + */ + private readonly TokenService $tokenService; public function __construct( private readonly TokenService $tokenService, private readonly LogService $logService, Request $request ) { - $this->admin = $request->admin; + $admin = $request->admin; + if (!$admin) { + throw new \RuntimeException('管理員信息未找到。'); + } + $this->admin = $admin; } /** @@ -38,12 +41,21 @@ public function __construct( public function index(): JsonResponse { try { - $clients = Client::select([ + $query = Client::select([ 'id', 'name', 'llm_provider_id', 'created_at', - ])->get(); + ]); + + // 如果不是超級管理員,只能看到自己管理的客戶 + if (!$this->admin->isSuperAdmin()) { + $query->whereHas('admins', function ($query) { + $query->where('admin_id', $this->admin->id); + }); + } + + $clients = $query->get(); return $this->success([ 'items' => $clients->map(fn($client) => [ @@ -87,12 +99,25 @@ public function store(Request $request): JsonResponse ], ]); + // 檢查是否有權限管理該提供商 + if (!$this->admin->canManageLlmProvider($validated['llm_provider_id'])) { + return $this->error( + ErrorCode::FORBIDDEN, + '您無權使用該 LLM 提供商。' + ); + } + $validated['status'] = Client::STATUS_ACTIVE; $validated['rate_limit'] = config('llm.default_rate_limit', 60); $validated['timeout'] = config('llm.default_timeout', 30); $client = Client::create($validated); + // 如果不是超級管理員,需要建立關聯 + if (!$this->admin->isSuperAdmin()) { + $client->admins()->attach($this->admin->id); + } + $this->logService->logOperation( 'admin', $this->admin->id, diff --git a/app/Http/Controllers/Api/Admin/LlmProviderController.php b/app/Http/Controllers/Api/Admin/LlmProviderController.php index 583fa25..539f3d8 100644 --- a/app/Http/Controllers/Api/Admin/LlmProviderController.php +++ b/app/Http/Controllers/Api/Admin/LlmProviderController.php @@ -8,9 +8,6 @@ use App\Http\Controllers\Controller; use App\Models\Admin; use App\Models\LlmProvider; -use App\Services\LogService; -use App\Traits\ApiResponse; -use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; @@ -18,23 +15,29 @@ class LlmProviderController extends Controller { - use ApiResponse; + /** + * @var Admin + */ + private readonly Admin $admin; - private Admin $admin; - - public function __construct( - private readonly LogService $logService, - Request $request - ) { - $this->admin = $request->admin; + public function __construct(Request $request) + { + $admin = $request->admin; + if (!$admin instanceof Admin) { + throw new \RuntimeException('管理員信息未找到。'); + } + $this->admin = $admin; } /** * 獲取 LLM 提供商列表 + * + * @return JsonResponse */ public function index(): JsonResponse { try { + /** @var \Illuminate\Database\Eloquent\Builder $providers */ $providers = LlmProvider::select([ 'id', 'name', @@ -42,9 +45,30 @@ public function index(): JsonResponse 'api_url', 'status', 'created_at', - ])->get(); + ]); - return $this->success($providers); + // 如果不是超級管理員,只能看到自己管理的提供商 + if (!$this->admin->isSuperAdmin()) { + $providers->whereHas('clients', function ($query) { + $query->whereHas('admins', function ($query) { + $query->where('admin_id', $this->admin->id); + }); + }); + } + + /** @var \Illuminate\Database\Eloquent\Collection $providerList */ + $providerList = $providers->get(); + + return response()->json([ + 'items' => $providerList->map(fn($provider) => [ + 'id' => $provider->id, + 'name' => $provider->name, + 'service_name' => $provider->service_name, + 'api_url' => $provider->api_url, + 'status' => $provider->status, + 'created_at' => $provider->created_at->toIso8601String(), + ]) + ]); } catch (\Exception $e) { Log::error('Error fetching LLM providers', [ @@ -52,19 +76,37 @@ public function index(): JsonResponse 'trace' => $e->getTraceAsString(), ]); - return $this->error( - ErrorCode::SERVER_ERROR, - ErrorCode::getMessage(ErrorCode::SERVER_ERROR) - ); + return response()->json([ + 'error' => ErrorCode::SERVER_ERROR, + 'message' => ErrorCode::getMessage(ErrorCode::SERVER_ERROR) + ]); } } /** * 新增 LLM 提供商 + * + * @param Request $request + * @return JsonResponse + * @throws ValidationException */ public function store(Request $request): JsonResponse { try { + // 只有超級管理員可以新增提供商 + if (!$this->admin->isSuperAdmin()) { + return response()->json([ + 'error' => ErrorCode::FORBIDDEN, + 'message' => '只有超級管理員可以新增 LLM 提供商。' + ]); + } + + /** @var array{ + * name: string, + * service_name: string, + * api_url: string, + * api_token: string + * } $validated */ $validated = $request->validate([ 'name' => [ 'required', @@ -91,15 +133,11 @@ public function store(Request $request): JsonResponse ]); $validated['status'] = LlmProvider::STATUS_ACTIVE; + + /** @var LlmProvider $provider */ $provider = LlmProvider::create($validated); - $this->logService->logOperation( - 'admin', - $this->admin->id, - "Created LLM provider: {$provider->name}" - ); - - return $this->created([ + return response()->json([ 'id' => $provider->id, 'name' => $provider->name, 'service_name' => $provider->service_name, @@ -109,11 +147,11 @@ public function store(Request $request): JsonResponse ]); } catch (ValidationException $e) { - return $this->error( - ErrorCode::VALIDATION_ERROR, - ErrorCode::getMessage(ErrorCode::VALIDATION_ERROR), - $e->errors() - ); + return response()->json([ + 'error' => ErrorCode::VALIDATION_ERROR, + 'message' => ErrorCode::getMessage(ErrorCode::VALIDATION_ERROR), + 'errors' => $e->errors() + ]); } catch (\Exception $e) { Log::error('Error creating LLM provider', [ 'error' => $e->getMessage(), @@ -121,10 +159,10 @@ public function store(Request $request): JsonResponse 'request_data' => $request->except(['api_token']), ]); - return $this->error( - ErrorCode::SERVER_ERROR, - ErrorCode::getMessage(ErrorCode::SERVER_ERROR) - ); + return response()->json([ + 'error' => ErrorCode::SERVER_ERROR, + 'message' => ErrorCode::getMessage(ErrorCode::SERVER_ERROR) + ]); } } @@ -137,10 +175,10 @@ public function update(Request $request, int $id): JsonResponse $provider = LlmProvider::findOrFail($id); if (!$this->admin->canManageLlmProvider($provider->id)) { - return $this->error( - ErrorCode::FORBIDDEN, - '您無權管理該 LLM 提供商。' - ); + return response()->json([ + 'error' => ErrorCode::FORBIDDEN, + 'message' => '您無權管理該 LLM 提供商。' + ]); } $validated = $request->validate([ @@ -177,22 +215,16 @@ public function update(Request $request, int $id): JsonResponse if ($validated['status'] === LlmProvider::STATUS_INACTIVE && $provider->status === LlmProvider::STATUS_ACTIVE) { if ($provider->clients()->exists()) { - return $this->error( - ErrorCode::RESOURCE_IN_USE, - '該提供商正在被客戶使用,無法停用。' - ); + return response()->json([ + 'error' => ErrorCode::RESOURCE_IN_USE, + 'message' => '該提供商正在被客戶使用,無法停用。' + ]); } } $provider->update($validated); - $this->logService->logOperation( - 'admin', - $this->admin->id, - "Updated LLM provider: {$provider->name}" - ); - - return $this->success([ + return response()->json([ 'id' => $provider->id, 'name' => $provider->name, 'service_name' => $provider->service_name, @@ -202,16 +234,11 @@ public function update(Request $request, int $id): JsonResponse ]); } catch (ValidationException $e) { - return $this->error( - ErrorCode::VALIDATION_ERROR, - ErrorCode::getMessage(ErrorCode::VALIDATION_ERROR), - $e->errors() - ); - } catch (ModelNotFoundException $e) { - return $this->error( - ErrorCode::RESOURCE_NOT_FOUND, - ErrorCode::getMessage(ErrorCode::RESOURCE_NOT_FOUND) - ); + return response()->json([ + 'error' => ErrorCode::VALIDATION_ERROR, + 'message' => ErrorCode::getMessage(ErrorCode::VALIDATION_ERROR), + 'errors' => $e->errors() + ]); } catch (\Exception $e) { Log::error('Error updating LLM provider', [ 'error' => $e->getMessage(), @@ -220,10 +247,10 @@ public function update(Request $request, int $id): JsonResponse 'request_data' => $request->except(['api_token']), ]); - return $this->error( - ErrorCode::SERVER_ERROR, - ErrorCode::getMessage(ErrorCode::SERVER_ERROR) - ); + return response()->json([ + 'error' => ErrorCode::SERVER_ERROR, + 'message' => ErrorCode::getMessage(ErrorCode::SERVER_ERROR) + ]); } } @@ -236,36 +263,27 @@ public function destroy(int $id): JsonResponse $provider = LlmProvider::findOrFail($id); if (!$this->admin->canManageLlmProvider($provider->id)) { - return $this->error( - ErrorCode::FORBIDDEN, - '您無權管理該 LLM 提供商。' - ); + return response()->json([ + 'error' => ErrorCode::FORBIDDEN, + 'message' => '您無權管理該 LLM 提供商。' + ]); } // 檢查是否有客戶在使用 if ($provider->clients()->exists()) { - return $this->error( - ErrorCode::RESOURCE_IN_USE, - '該提供商正在被客戶使用,無法刪除。' - ); + return response()->json([ + 'error' => ErrorCode::RESOURCE_IN_USE, + 'message' => '該提供商正在被客戶使用,無法刪除。' + ]); } $providerName = $provider->name; $provider->delete(); - $this->logService->logOperation( - 'admin', - $this->admin->id, - "Deleted LLM provider: {$providerName}" - ); + return response()->json([ + 'message' => 'LLM 提供商已刪除。' + ]); - return $this->success(null, 'LLM 提供商已刪除。'); - - } catch (ModelNotFoundException $e) { - return $this->error( - ErrorCode::RESOURCE_NOT_FOUND, - ErrorCode::getMessage(ErrorCode::RESOURCE_NOT_FOUND) - ); } catch (\Exception $e) { Log::error('Error deleting LLM provider', [ 'error' => $e->getMessage(), @@ -273,10 +291,10 @@ public function destroy(int $id): JsonResponse 'provider_id' => $id, ]); - return $this->error( - ErrorCode::SERVER_ERROR, - ErrorCode::getMessage(ErrorCode::SERVER_ERROR) - ); + return response()->json([ + 'error' => ErrorCode::SERVER_ERROR, + 'message' => ErrorCode::getMessage(ErrorCode::SERVER_ERROR) + ]); } } } diff --git a/app/Http/Controllers/Api/AuthController.php b/app/Http/Controllers/Api/AuthController.php index dacb02b..0861c4b 100644 --- a/app/Http/Controllers/Api/AuthController.php +++ b/app/Http/Controllers/Api/AuthController.php @@ -7,7 +7,6 @@ use App\Constants\ErrorCode; use App\Http\Controllers\Controller; use App\Services\Auth\TokenService; -use App\Traits\ApiResponse; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; @@ -15,25 +14,35 @@ class AuthController extends Controller { - use ApiResponse; + /** + * @var TokenService + */ + private readonly TokenService $tokenService; - public function __construct( - private readonly TokenService $tokenService, - ) {} + public function __construct(TokenService $tokenService) + { + $this->tokenService = $tokenService; + } /** * 獲取訪問令牌 + * + * @param Request $request + * @return JsonResponse + * @throws ValidationException */ public function getAccessToken(Request $request): JsonResponse { try { + /** @var array{auth_token: string} $validated */ $validated = $request->validate([ 'auth_token' => 'required|string|size:64', ]); + /** @var array{client_id: int, expires_at: string}|null $authTokenData */ $authTokenData = $this->tokenService->validateAuthToken($validated['auth_token']); - if (!$authTokenData) { + if (!$authTokenData || !isset($authTokenData['expires_at'])) { return $this->error( ErrorCode::TOKEN_INVALID, '認證令牌無效。' @@ -47,9 +56,17 @@ public function getAccessToken(Request $request): JsonResponse ); } + /** @var array{access_token: string, expires_in: int} $result */ $result = $this->tokenService->generateAccessToken($authTokenData); - return $this->success($result); + if (!isset($result['access_token']) || !isset($result['expires_in'])) { + throw new \RuntimeException('生成訪問令牌失敗。'); + } + + return $this->success([ + 'access_token' => $result['access_token'], + 'expires_in' => $result['expires_in'], + ]); } catch (ValidationException $e) { return $this->error( diff --git a/app/Http/Controllers/Api/LlmController.php b/app/Http/Controllers/Api/LlmController.php index 8275aba..9fd4291 100644 --- a/app/Http/Controllers/Api/LlmController.php +++ b/app/Http/Controllers/Api/LlmController.php @@ -7,7 +7,6 @@ use App\Constants\ErrorCode; use App\Http\Controllers\Controller; use App\Services\LlmService; -use App\Traits\ApiResponse; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; @@ -15,18 +14,38 @@ class LlmController extends Controller { - use ApiResponse; + /** + * @var LlmService + */ + private readonly LlmService $llmService; - public function __construct( - private readonly LlmService $llmService, - ) {} + public function __construct(LlmService $llmService) + { + $this->llmService = $llmService; + } /** * 發送 LLM 請求 + * + * @param Request $request + * @return JsonResponse + * @throws ValidationException|\RuntimeException */ public function request(Request $request): JsonResponse { try { + if (!$request->client) { + throw new \RuntimeException('客戶信息未找到。'); + } + + /** @var array{ + * prompt: string, + * max_tokens?: int, + * temperature?: float, + * top_p?: float, + * frequency_penalty?: float, + * presence_penalty?: float + * } $validated */ $validated = $request->validate([ 'prompt' => 'required|string|max:4000', 'max_tokens' => 'nullable|integer|min:1|max:4000', @@ -36,12 +55,17 @@ public function request(Request $request): JsonResponse 'presence_penalty' => 'nullable|numeric|min:-2|max:2', ]); + /** @var array{response: string} $result */ $result = $this->llmService->sendRequest( $request->client, $validated['prompt'], array_filter($validated, fn($key) => $key !== 'prompt', ARRAY_FILTER_USE_KEY) ); + if (!isset($result['response'])) { + throw new \RuntimeException('LLM 提供商返回的響應格式無效。'); + } + return $this->success([ 'response' => $result['response'], ]); diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 8677cd5..9faa3eb 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -1,8 +1,103 @@ true, + ]; + + if ($data !== null) { + $response['data'] = $data; + } + + if ($message !== null) { + $response['message'] = $message; + } + + return response()->json($response, $code); + } + + /** + * 错误响应 + * + * @param string $error 错误代码 + * @param string $message 错误消息 + * @param mixed $errors 详细错误信息 + * @param int $code HTTP状态码 + */ + protected function error( + string $error, + string $message, + mixed $errors = null, + int $code = Response::HTTP_BAD_REQUEST + ): JsonResponse { + $response = [ + 'success' => false, + 'error' => $error, + 'message' => $message, + ]; + + if ($errors !== null) { + $response['errors'] = $errors; + } + + return response()->json($response, $code); + } + + /** + * 分页响应 + * + * @param array $items 分页数据 + * @param array $meta 分页元数据 + * @param string|null $message 成功消息 + */ + protected function paginate(array $items, array $meta, ?string $message = null): JsonResponse + { + $response = [ + 'success' => true, + 'data' => $items, + 'meta' => $meta, + ]; + + if ($message !== null) { + $response['message'] = $message; + } + + return response()->json($response); + } + + /** + * 创建成功响应 + * + * @param mixed $data 创建的资源数据 + * @param string|null $message 成功消息 + */ + protected function created(mixed $data, ?string $message = null): JsonResponse + { + return $this->success($data, $message, Response::HTTP_CREATED); + } + + /** + * 无内容响应 + */ + protected function noContent(): JsonResponse + { + return response()->json(null, Response::HTTP_NO_CONTENT); + } } diff --git a/app/Models/Admin.php b/app/Models/Admin.php index 9ce1915..d1f851a 100644 --- a/app/Models/Admin.php +++ b/app/Models/Admin.php @@ -40,10 +40,13 @@ class Admin extends Authenticatable 'role' => 'string', ]; + /** + * @return BelongsToMany + */ public function clients(): BelongsToMany { return $this->belongsToMany(Client::class, 'admin_client') - ->withTimestamp('assigned_at'); + ->withTimestamps(); } /** @@ -72,6 +75,8 @@ public function isValidAdmin(): bool /** * 检查是否可以管理指定的客户 + * + * @param int $clientId */ public function canManageClient(int $clientId): bool { @@ -84,6 +89,8 @@ public function canManageClient(int $clientId): bool /** * 检查是否可以管理指定的LLM提供商 + * + * @param int $providerId */ public function canManageLlmProvider(int $providerId): bool { diff --git a/app/Models/Client.php b/app/Models/Client.php index 47a7349..ac46669 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -40,11 +40,17 @@ class Client extends Model 'status' => 'string', ]; + /** + * @return BelongsTo + */ public function llmProvider(): BelongsTo { return $this->belongsTo(LlmProvider::class); } + /** + * @return BelongsToMany + */ public function admins(): BelongsToMany { return $this->belongsToMany(Admin::class, 'admin_client') @@ -64,6 +70,8 @@ public function isActive(): bool */ public function canSendLlmRequest(): bool { - return $this->isActive() && $this->llmProvider->isActive(); + /** @var LlmProvider|null $provider */ + $provider = $this->llmProvider; + return $this->isActive() && $provider && $provider->isActive(); } } diff --git a/app/Models/LlmProvider.php b/app/Models/LlmProvider.php index d463a02..83df411 100644 --- a/app/Models/LlmProvider.php +++ b/app/Models/LlmProvider.php @@ -41,6 +41,9 @@ class LlmProvider extends Model 'status' => 'string', ]; + /** + * @return HasMany + */ public function clients(): HasMany { return $this->hasMany(Client::class); diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 319ef60..6213f0a 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -1,3 +1,4 @@ +isAfter($data['expires_at'])) { Redis::del(self::AUTH_TOKEN_PREFIX . $token); @@ -125,16 +130,20 @@ public function generateAccessToken(array $authTokenData): array /** * 驗證訪問令牌 * + * @param string $token * @return array{client_id: int, auth_token: string, created_at: string}|null */ public function validateAccessToken(string $token): ?array { + /** @var string|null $tokenData */ $tokenData = Redis::get(self::ACCESS_TOKEN_PREFIX . $token); if (!$tokenData) { return null; } - return json_decode($tokenData, true); + /** @var array{client_id: int, auth_token: string, created_at: string}|null $data */ + $data = json_decode($tokenData, true); + return $data; } /** diff --git a/app/Services/LlmService.php b/app/Services/LlmService.php index 1529616..0b9922a 100644 --- a/app/Services/LlmService.php +++ b/app/Services/LlmService.php @@ -32,6 +32,7 @@ public function sendRequest(Client $client, string $prompt, array $options = []) } try { + /** @var \App\Models\LlmProvider $provider */ $provider = $client->llmProvider; if ($provider->status !== 'active') { diff --git a/app/Traits/ApiResponse.php b/app/Traits/ApiResponse.php deleted file mode 100644 index 51f4cb2..0000000 --- a/app/Traits/ApiResponse.php +++ /dev/null @@ -1,109 +0,0 @@ - true, - ]; - - if ($data !== null) { - $response['data'] = $data; - } - - if ($message !== null) { - $response['message'] = $message; - } - - return response()->json($response, $code); - } - - /** - * 错误响应 - * - * @param string $error 错误代码 - * @param string $message 错误消息 - * @param mixed $errors 详细错误信息 - * @param int $code HTTP状态码 - * @return JsonResponse - */ - protected function error( - string $error, - string $message, - mixed $errors = null, - int $code = Response::HTTP_BAD_REQUEST - ): JsonResponse { - $response = [ - 'success' => false, - 'error' => $error, - 'message' => $message, - ]; - - if ($errors !== null) { - $response['errors'] = $errors; - } - - return response()->json($response, $code); - } - - /** - * 分页响应 - * - * @param array $items 分页数据 - * @param array $meta 分页元数据 - * @param string|null $message 成功消息 - * @return JsonResponse - */ - protected function paginate(array $items, array $meta, ?string $message = null): JsonResponse - { - $response = [ - 'success' => true, - 'data' => $items, - 'meta' => $meta, - ]; - - if ($message !== null) { - $response['message'] = $message; - } - - return response()->json($response); - } - - /** - * 创建成功响应 - * - * @param mixed $data 创建的资源数据 - * @param string|null $message 成功消息 - * @return JsonResponse - */ - protected function created(mixed $data, ?string $message = null): JsonResponse - { - return $this->success($data, $message, Response::HTTP_CREATED); - } - - /** - * 无内容响应 - * - * @return JsonResponse - */ - protected function noContent(): JsonResponse - { - return response()->json(null, Response::HTTP_NO_CONTENT); - } -}