query('username', '')); if ($username !== '') { $q->where('username', 'like', '%'.$username.'%'); } $sortable = ['id', 'username', 'is_super', 'status', 'created_at', 'updated_at']; $field = (string) $request->query('field', 'id'); $order = strtolower((string) $request->query('order', 'desc')) === 'asc' ? 'asc' : 'desc'; if (! in_array($field, $sortable, true)) { $field = 'id'; } $q->orderBy($field, $order); $limit = max(1, min(100, (int) $request->query('limit', 20))); $page = max(1, (int) $request->query('page', 1)); $paginator = $q->paginate($limit, ['*'], 'page', $page); $selfId = (int) auth('admin')->id(); $data = collect($paginator->items())->map(function (Admin $a) use ($selfId) { return [ 'id' => $a->id, 'username' => $a->username, 'is_super' => (int) $a->is_super, 'status' => (int) $a->status, 'google_auth_open' => (int) $a->google_auth_open, 'last_ip' => $a->last_ip, 'login_attempts' => (int) $a->login_attempts, 'locked_at' => optional($a->locked_at)->format('Y-m-d H:i:s'), 'is_locked' => $a->isLocked(), 'created_at' => optional($a->created_at)->format('Y-m-d H:i:s'), 'updated_at' => optional($a->updated_at)->format('Y-m-d H:i:s'), 'is_self' => $a->id === $selfId, ]; })->values(); return response()->json([ 'code' => 0, 'msg' => '', 'count' => $paginator->total(), 'data' => $data, ]); } public function store(Request $request) { $data = $request->validate([ 'username' => ['required', 'string', 'max:64', 'alpha_dash', Rule::unique('admins', 'username')], 'password' => ['required', 'string', 'min:6', 'max:128'], 'is_super' => ['nullable', 'integer', Rule::in([0, 1])], 'status' => ['nullable', 'integer', Rule::in([0, 1])], ]); $admin = Admin::query()->create([ 'username' => $data['username'], 'password' => $data['password'], 'is_super' => (int) ($data['is_super'] ?? 0), 'status' => (int) ($data['status'] ?? 1), ]); return response()->json(['code' => 0, 'msg' => 'ok', 'data' => ['id' => $admin->id]]); } public function update(Request $request, Admin $adminUser) { $data = $request->validate([ 'password' => ['nullable', 'string', 'min:6', 'max:128'], 'is_super' => ['nullable', 'integer', Rule::in([0, 1])], 'status' => ['nullable', 'integer', Rule::in([0, 1])], ]); if (array_key_exists('is_super', $data) && $data['is_super'] !== null) { $newSuper = (int) $data['is_super']; if ($adminUser->isSuper() && $newSuper === 0 && $this->superCount() <= 1) { return response()->json(['code' => 1, 'msg' => '至少保留一名超级管理员'], 422); } $adminUser->is_super = $newSuper; } if (array_key_exists('status', $data) && $data['status'] !== null) { if ((int) $adminUser->id === (int) auth('admin')->id() && (int) $data['status'] === 0) { return response()->json(['code' => 1, 'msg' => '不能禁用当前登录账号'], 422); } $adminUser->status = (int) $data['status']; } if (! empty($data['password'])) { $adminUser->password = $data['password']; } $adminUser->save(); return response()->json(['code' => 0, 'msg' => 'ok']); } public function destroy(Admin $adminUser) { if ((int) $adminUser->id === (int) auth('admin')->id()) { return response()->json(['code' => 1, 'msg' => '不能删除当前登录账号'], 422); } if ($adminUser->isSuper() && $this->superCount() <= 1) { return response()->json(['code' => 1, 'msg' => '不能删除最后一名超级管理员'], 422); } $adminUser->delete(); return response()->json(['code' => 0, 'msg' => 'ok']); } /** * Unlock an admin account that was locked due to too many failed * password attempts. Only super admins can unlock. */ public function unlock(Admin $adminUser) { /** @var Admin $actor */ $actor = auth('admin')->user(); if (! $actor instanceof Admin || ! $actor->isSuper()) { return response()->json(['code' => 1, 'msg' => '需要超级管理员权限'], 403); } if (! $adminUser->isLocked()) { return response()->json(['code' => 1, 'msg' => '该账号未被封禁']); } $adminUser->clearLoginAttempts(); SystemLog::record( $actor, 'admin', SystemLog::ACTION_ADMIN_UNLOCKED, '超级管理员「'.$actor->username.'」解除管理员「'.$adminUser->username.'」的封禁状态', request(), ); return response()->json(['code' => 0, 'msg' => '已解除封禁']); } private function superCount(): int { return (int) Admin::query()->where('is_super', 1)->count(); } }