让分类、会员和示例工具共用同一账号,本地即可跑通登录与授权。 Co-authored-by: Cursor <cursoragent@cursor.com>
90 lines
3.2 KiB
PHP
90 lines
3.2 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\V1\Admin;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\AuditLog;
|
|
use App\Models\Plan;
|
|
use App\Models\User;
|
|
use App\Services\AuthService;
|
|
use App\Services\MembershipService;
|
|
use App\Support\Presenter;
|
|
use Illuminate\Http\Request;
|
|
|
|
class PeopleController extends Controller
|
|
{
|
|
public function __construct(
|
|
private readonly MembershipService $membership,
|
|
private readonly AuthService $auth,
|
|
) {}
|
|
|
|
public function users(Request $request)
|
|
{
|
|
$query = User::query()->with('identities', 'subscription.plan');
|
|
if ($keyword = trim((string) $request->query('q', ''))) {
|
|
$like = '%'.addcslashes($keyword, '%_\\').'%';
|
|
$query->where(function ($q) use ($like) {
|
|
$q->where('nickname', 'like', $like)
|
|
->orWhereHas('identities', fn ($identity) => $identity->where('identifier', 'like', $like));
|
|
});
|
|
}
|
|
$page = $query->latest()->paginate(15);
|
|
|
|
return $this->ok([
|
|
'items' => collect($page->items())->map(fn (User $user) => Presenter::user($user, true))->values(),
|
|
'total' => $page->total(),
|
|
'page' => $page->currentPage(),
|
|
]);
|
|
}
|
|
|
|
public function updateUser(Request $request, User $user)
|
|
{
|
|
$data = $request->validate([
|
|
'status' => ['required', 'in:active,disabled'],
|
|
'disabled_reason' => ['nullable', 'string', 'max:255'],
|
|
]);
|
|
if ($user->id === $request->user()->id && $data['status'] !== 'active') {
|
|
return response()->json(['message' => '不能停用当前登录账号', 'code' => 'self'], 422);
|
|
}
|
|
$user->update($data);
|
|
if ($data['status'] !== 'active') {
|
|
$this->auth->revokeTokens($user);
|
|
}
|
|
$this->audit($request->user(), 'user.update', $user, '更新用户状态 '.$user->nickname);
|
|
|
|
return $this->ok(Presenter::user($user->refresh(), true));
|
|
}
|
|
|
|
public function grant(Request $request, User $user)
|
|
{
|
|
$data = $request->validate([
|
|
'plan_code' => ['required', 'string'],
|
|
'days' => ['required', 'integer', 'min:0', 'max:3650'],
|
|
]);
|
|
if ($data['days'] === 0) {
|
|
$this->membership->stop($user);
|
|
$this->audit($request->user(), 'membership.stop', $user, '停用会员 '.$user->nickname);
|
|
|
|
return $this->ok(Presenter::user($user->refresh(), true), '会员已停用');
|
|
}
|
|
$plan = Plan::query()->where('code', $data['plan_code'])->firstOrFail();
|
|
$this->membership->grant($user, $plan, now()->addDays($data['days']));
|
|
$this->audit($request->user(), 'membership.grant', $user, '开通 '.$plan->name.' '.$data['days'].' 天');
|
|
|
|
return $this->ok(Presenter::user($user->refresh(), true), '会员已开通');
|
|
}
|
|
|
|
public function audits()
|
|
{
|
|
$rows = AuditLog::query()->with('actor:id,nickname')->latest()->limit(100)->get();
|
|
|
|
return $this->ok($rows->map(fn (AuditLog $row) => [
|
|
'id' => $row->id,
|
|
'action' => $row->action,
|
|
'summary' => $row->summary,
|
|
'actor' => $row->actor?->nickname,
|
|
'created_at' => $row->created_at?->toIso8601String(),
|
|
]));
|
|
}
|
|
}
|