json(['message' => '请使用平台统一核销入口'], 404); } public function login(Request $request): JsonResponse { $data = $request->validate([ 'portal_code' => ['nullable', 'string', 'max:16'], 'portal_token' => ['nullable', 'string', 'max:64'], 'username' => ['nullable', 'string', 'max:64'], 'password' => ['required', 'string', 'max:72'], ]); $password = (string) ($data['password'] ?? ''); $passwordTrim = trim($password); $usernameInput = trim((string) ($data['username'] ?? '')); if (preg_match('/^\d{6}$/', $passwordTrim)) { if ($usernameInput !== '') { return response()->json(['message' => '核销只需输入 6 位数字口令,无需用户名'], 422); } /** @var Activity|null $activity */ $activity = Activity::query()->where('verify_portal_pin', $passwordTrim)->first(); if ($activity !== null) { $cred = ActivityVerifyPortalPin::syncPinCredential($activity); if (! Hash::check($passwordTrim, $cred->password)) { $cred = ActivityVerifyPortalPin::syncPinCredential($activity->fresh()); if (! Hash::check($passwordTrim, $cred->password)) { return response()->json(['message' => '系统繁忙,请稍后再试'], 500); } } if (! $cred->portalAcceptsVerification()) { return response()->json(['message' => '活动已结束,无法登录核销'], 422); } $expiresAt = now()->addMonths(6); /** 活动核销允许多人并行在线 */ $plain = $cred->createToken('verify-portal', ['verify-portal'], $expiresAt)->plainTextToken; return response()->json([ 'token' => $plain, 'auth_mode' => 'verify_portal', 'portal_kind' => VerifyPortalCredential::KIND_ACTIVITY, 'portal_id' => (int) $activity->id, ]); } /** @var Venue|null $venue */ $venue = Venue::query()->where('verify_portal_pin', $passwordTrim)->first(); if ($venue !== null) { $cred = VenueVerifyPortalPin::syncPinCredential($venue); if (! Hash::check($passwordTrim, $cred->password)) { $cred = VenueVerifyPortalPin::syncPinCredential($venue->fresh()); if (! Hash::check($passwordTrim, $cred->password)) { return response()->json(['message' => '系统繁忙,请稍后再试'], 500); } } if (! $cred->portalAcceptsVerification()) { return response()->json(['message' => '该场馆核销入口不可用(未启用或未通过审核),无法登录核销'], 422); } $expiresAt = now()->addMonths(6); /** 与活动一致:不因新登录吊销旧 token */ $plain = $cred->createToken('verify-portal', ['verify-portal'], $expiresAt)->plainTextToken; return response()->json([ 'token' => $plain, 'auth_mode' => 'verify_portal', 'portal_kind' => VerifyPortalCredential::KIND_TICKET_GRAB_VENUE, 'portal_id' => (int) $venue->id, ]); } return response()->json(['message' => '密码错误'], 422); } return response()->json([ 'message' => '请使用后台账号用户名与密码登录,或直接输入 6 位数字核销口令(活动或抢票场馆口令)。', ], 422); } public function me(Request $request): JsonResponse { $cred = $request->user(); if (! $cred instanceof VerifyPortalCredential) { return response()->json(['message' => '非核销门户登录态'], 403); } if (! $cred->portalAcceptsVerification()) { $cred->tokens()->delete(); return response()->json(['message' => '核销已失效'], 403); } $cred->load('venue:id,name'); $title = ''; if ($cred->portal_kind === VerifyPortalCredential::KIND_ACTIVITY) { $title = (string) Activity::query()->where('id', $cred->portal_id)->value('title'); } elseif ($cred->portal_kind === VerifyPortalCredential::KIND_TICKET_GRAB_VENUE) { $title = '抢票 · '.(string) ($cred->venue?->name ?? ''); } else { $title = (string) TicketGrabEvent::query()->where('id', $cred->portal_id)->value('title'); } $hidePinUser = \in_array( (string) $cred->username, [ActivityVerifyPortalPin::CRED_USERNAME, VenueVerifyPortalPin::CRED_USERNAME], true, ); return response()->json([ 'auth_mode' => 'verify_portal', 'portal_kind' => $cred->portal_kind, 'portal_id' => $cred->portal_id, 'username' => $hidePinUser ? null : $cred->username, 'venue' => $cred->venue ? ['id' => $cred->venue->id, 'name' => $cred->venue->name] : null, 'event_title' => $title, ]); } }