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(), ])); } }