master
lion 6 days ago
parent 57aa6411a3
commit 68ad86e4a3

@ -15,6 +15,7 @@ use Illuminate\Validation\ValidationException;
class ActivityBookingController extends Controller
{
use AuthorizesActivitySubmitter;
private const BOOKING_MODE_INDIVIDUAL = 'individual';
private const BOOKING_MODE_GROUP = 'group';
@ -23,16 +24,15 @@ class ActivityBookingController extends Controller
public function show(Request $request, Activity $activity): JsonResponse
{
$this->ensureVenuePermission($request, $activity->venue_id);
$this->authorizeActivityEditForNonSuperAdmin($request, $activity);
$this->authorizeActivityCollaboratorView($request, $activity);
return response()->json($this->formatBookingPayload($activity->load('venue:id,appointment_type')));
}
public function update(Request $request, Activity $activity): JsonResponse
{
$this->ensureVenuePermission($request, $activity->venue_id);
$this->authorizeActivityEditForNonSuperAdmin($request, $activity);
$this->ensureVenueOrCreatorPermission($request, $activity);
$this->authorizeActivityFullEdit($request, $activity);
if (($activity->reservation_type ?? Activity::RESERVATION_TYPE_ONLINE) !== Activity::RESERVATION_TYPE_ONLINE) {
throw ValidationException::withMessages([
@ -67,7 +67,12 @@ class ActivityBookingController extends Controller
$maxPeople = max(1, $maxPeople);
if ($maxPeople < $minPeople) {
throw ValidationException::withMessages([
'max_people_per_order' => ['最大预约人数不能小于最小预约人数'],
'max_people_per_order' => ['每单最多人数不能小于每单最少人数'],
]);
}
if ($maxPeople === 1) {
throw ValidationException::withMessages([
'max_people_per_order' => ['团体或个人+团体模式下,每单最多人数须大于等于每单最少人数,且不可为 1请至少设为 2'],
]);
}
}
@ -156,6 +161,13 @@ class ActivityBookingController extends Controller
$activity->load('activityDays');
$activity->forceFill(['schedule_status' => Activity::computeScheduleStatusForDisplay($activity)])->saveQuietly();
if (! $request->user()?->isSuperAdmin()) {
$activity->forceFill([
'audit_status' => Activity::AUDIT_PENDING,
'audit_remark' => null,
])->save();
}
return response()->json(array_merge(
['message' => '保存成功'],
$this->formatBookingPayload($activity->fresh()->load('venue:id,appointment_type'))
@ -277,14 +289,4 @@ class ActivityBookingController extends Controller
'days' => $days,
];
}
private function ensureVenuePermission(Request $request, int $venueId): void
{
$user = $request->user();
if ($user->isSuperAdmin()) {
return;
}
$allowed = $user->venues()->where('venues.id', $venueId)->exists();
abort_unless($allowed, 403, '仅可操作已绑定场馆');
}
}

@ -2,9 +2,11 @@
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Concerns\AuthorizesActivitySubmitter;
use App\Http\Controllers\Controller;
use App\Models\Activity;
use App\Models\ActivityAuditLog;
use App\Support\ActivityVerifyPortalPin;
use App\Support\VerifyPortalCode;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
@ -15,9 +17,41 @@ use Illuminate\Validation\ValidationException;
class ActivityController extends Controller
{
use AuthorizesActivitySubmitter;
public function auditLogs(Request $request, Activity $activity): JsonResponse
{
$this->authorizeActivityCollaboratorView($request, $activity);
$rows = ActivityAuditLog::query()
->where('activity_id', $activity->id)
->with(['adminUser:id,name'])
->orderByDesc('created_at')
->get()
->map(static function (ActivityAuditLog $log) {
return [
'id' => $log->id,
'action' => $log->action,
'remark' => $log->remark,
'created_at' => $log->created_at?->toIso8601String(),
'admin_user' => $log->adminUser ? [
'id' => $log->adminUser->id,
'name' => $log->adminUser->name,
] : null,
];
});
return response()->json(['data' => $rows]);
}
public function index(Request $request): JsonResponse
{
$query = Activity::with(['venue:id,name', 'activityDays'])->orderByHotThenScheduleStatusPriority();
$query = Activity::with(['venue:id,name', 'activityDays', 'submitter:id,name'])
->withCount([
'auditLogs as approve_audit_logs_count' => function ($rel) {
$rel->where('action', ActivityAuditLog::ACTION_APPROVE);
},
])
->orderByHotThenScheduleStatusPriority();
$this->restrictByVenue($request, $query);
if ($request->filled('keyword')) {
@ -93,7 +127,7 @@ class ActivityController extends Controller
'is_hot' => ['sometimes', 'boolean'],
]);
if (! $request->user()?->isSuperAdmin()) {
unset($data['is_hot']);
unset($data['is_hot'], $data['is_active']);
}
$data = $this->applyReservationTypeDefaults($data);
$this->assertTicketNoteWhenNeeded($data, null);
@ -125,6 +159,8 @@ class ActivityController extends Controller
}
VerifyPortalCode::ensureForActivity($activity);
ActivityVerifyPortalPin::ensure($activity);
$activity->load('activityDays');
$activity->forceFill(['schedule_status' => Activity::computeScheduleStatusForDisplay($activity)])->saveQuietly();
@ -138,8 +174,8 @@ class ActivityController extends Controller
public function update(Request $request, Activity $activity): JsonResponse
{
$this->ensureVenuePermission($request, $activity->venue_id);
$this->authorizeActivityEditForNonSuperAdmin($request, $activity);
$this->ensureVenueOrCreatorPermission($request, $activity);
$this->authorizeActivityFullEdit($request, $activity);
$data = $request->validate([
'venue_id' => ['sometimes', 'integer', 'exists:venues,id'],
@ -184,7 +220,7 @@ class ActivityController extends Controller
}
$user = $request->user();
if (! $user?->isSuperAdmin()) {
unset($data['sort'], $data['is_hot']);
unset($data['sort'], $data['is_hot'], $data['is_active']);
/** 场馆编辑(含已结束、已退回)后均进入待审核,由超级管理员再次审核 */
$data['audit_status'] = Activity::AUDIT_PENDING;
$data['audit_remark'] = null;
@ -205,6 +241,21 @@ class ActivityController extends Controller
$activity->load('activityDays');
$activity->forceFill(['schedule_status' => Activity::computeScheduleStatusForDisplay($activity)])->saveQuietly();
try {
ActivityVerifyPortalPin::ensure($activity->fresh());
} catch (\Throwable) {
// 后台稍后打开核销页会补齐
}
if ($user && ! $user->isSuperAdmin()) {
ActivityAuditLog::query()->create([
'activity_id' => $activity->id,
'admin_user_id' => $user->id,
'action' => ActivityAuditLog::ACTION_EDIT_SUBMIT,
'remark' => null,
]);
}
$fresh = $activity->fresh()->load(['venue:id,name', 'activityDays']);
if (! $request->user()?->isSuperAdmin()) {
$fresh->makeHidden(['is_hot']);
@ -220,6 +271,7 @@ class ActivityController extends Controller
$data = $request->validate([
'mark_hot' => ['required', 'boolean'],
'remark' => ['nullable', 'string', 'max:2000'],
]);
$activity->audit_status = Activity::AUDIT_APPROVED;
@ -228,12 +280,19 @@ class ActivityController extends Controller
$activity->is_hot = (bool) $data['mark_hot'];
$activity->save();
ActivityAuditLog::query()->create([
'activity_id' => $activity->id,
'admin_user_id' => $request->user()->id,
'action' => ActivityAuditLog::ACTION_APPROVE,
'remark' => $data['remark'] ?? null,
]);
return response()->json($activity->fresh()->load('venue:id,name'));
}
public function updateBehindScenes(Request $request, Activity $activity): JsonResponse
{
$this->ensureVenuePermission($request, $activity->venue_id);
$this->ensureVenueOrCreatorPermission($request, $activity);
$this->authorizeActivityBehindScenesEdit($request, $activity);
$status = Activity::computeScheduleStatusForDisplay($activity->load('activityDays'));
abort_unless($status === 'ended', 422, '仅已结束活动可上传花絮');
@ -282,13 +341,20 @@ class ActivityController extends Controller
$activity->audit_remark = $data['remark'] ?? null;
$activity->save();
ActivityAuditLog::query()->create([
'activity_id' => $activity->id,
'admin_user_id' => $request->user()->id,
'action' => ActivityAuditLog::ACTION_REJECT,
'remark' => $data['remark'] ?? null,
]);
return response()->json($activity->fresh()->load('venue:id,name'));
}
public function toggle(Request $request, Activity $activity): JsonResponse
{
$this->ensureVenuePermission($request, $activity->venue_id);
$this->authorizeActivityEditForNonSuperAdmin($request, $activity);
abort_unless($request->user()?->isSuperAdmin(), 403, '仅超级管理员可上下架活动');
$this->ensureVenueOrCreatorPermission($request, $activity);
$activity->is_active = ! $activity->is_active;
$activity->save();
@ -297,8 +363,16 @@ class ActivityController extends Controller
public function destroy(Request $request, Activity $activity): JsonResponse
{
$this->ensureVenuePermission($request, $activity->venue_id);
$this->authorizeActivityEditForNonSuperAdmin($request, $activity);
$this->ensureVenueOrCreatorPermission($request, $activity);
$this->authorizeActivityFullEdit($request, $activity);
if (
ActivityAuditLog::query()
->where('activity_id', $activity->id)
->where('action', ActivityAuditLog::ACTION_APPROVE)
->exists()
) {
return response()->json(['message' => '该活动曾审核通过,无法删除'], 422);
}
$count = $activity->reservations()->count();
if ($count > 0) {
return response()->json([
@ -314,8 +388,8 @@ class ActivityController extends Controller
public function restore(Request $request, int $activityId): JsonResponse
{
$activity = Activity::withTrashed()->findOrFail($activityId);
$this->ensureVenuePermission($request, $activity->venue_id);
$this->authorizeActivityEditForNonSuperAdmin($request, $activity);
$this->ensureVenueOrCreatorPermission($request, $activity);
$this->authorizeActivityFullEdit($request, $activity);
$disableAfterRestore = $request->boolean('disable_after_restore');
$activity->restore();
if ($disableAfterRestore) {

@ -43,6 +43,27 @@ class ActivityRegistrationController extends Controller
$query->whereIn('venue_id', $user->venues()->pluck('venues.id'));
}
if ($request->filled('venue_id')) {
$vid = (int) $request->input('venue_id');
if ($vid > 0) {
if (! $user->isSuperAdmin()) {
abort_unless(
$user->venues()->where('venues.id', $vid)->exists(),
403,
'仅可筛选已绑定场馆'
);
}
$query->where('venue_id', $vid);
}
}
if ($kind !== 'ticket_grab' && $request->filled('activity_id')) {
$aid = (int) $request->input('activity_id');
if ($aid > 0) {
$query->where('activity_id', $aid);
}
}
if ($kind === 'ticket_grab' && $request->filled('ticket_grab_event_id')) {
$eid = (int) $request->input('ticket_grab_event_id');
if ($eid > 0) {
@ -115,9 +136,28 @@ class ActivityRegistrationController extends Controller
})
->orderByDesc('id');
$user = $request->user();
if (!$user->isSuperAdmin()) {
if (! $user->isSuperAdmin()) {
$query->whereIn('venue_id', $user->venues()->pluck('venues.id'));
}
if ($request->filled('venue_id')) {
$vid = (int) $request->input('venue_id');
if ($vid > 0) {
if (! $user->isSuperAdmin()) {
abort_unless(
$user->venues()->where('venues.id', $vid)->exists(),
403,
'仅可筛选已绑定场馆'
);
}
$query->where('venue_id', $vid);
}
}
if ($request->filled('activity_id')) {
$aid = (int) $request->input('activity_id');
if ($aid > 0) {
$query->where('activity_id', $aid);
}
}
if ($request->filled('status') && $request->string('status')->toString() !== 'all') {
$query->where('status', (string) $request->string('status'));
}
@ -137,11 +177,11 @@ class ActivityRegistrationController extends Controller
}
$rows = $query->limit(5000)->get();
$filename = 'activity-registrations-' . now()->format('Ymd-His') . '.csv';
$filename = 'activity-registrations-'.now()->format('Ymd-His').'.csv';
return response()->streamDownload(function () use ($rows) {
$out = fopen('php://output', 'w');
fprintf($out, chr(0xEF) . chr(0xBB) . chr(0xBF));
fprintf($out, chr(0xEF).chr(0xBB).chr(0xBF));
fputcsv($out, ['ID', '活动', '场馆', '报名人', '手机号', '预约类型', '预约票数', '场次名称', '预约时间', '状态', '下单时间', '核销时间', '二维码Token']);
foreach ($rows as $row) {
$ad = $row->activityDay;
@ -170,12 +210,12 @@ class ActivityRegistrationController extends Controller
public function quickBlacklist(Request $request, Reservation $reservation): JsonResponse
{
$user = $request->user();
if (!$user->isSuperAdmin()) {
if (! $user->isSuperAdmin()) {
$allowed = $user->venues()->where('venues.id', $reservation->venue_id)->exists();
abort_unless($allowed, 403, '仅可操作已绑定场馆');
}
if (!$reservation->visitor_phone) {
if (! $reservation->visitor_phone) {
return response()->json(['message' => '该报名记录无手机号,无法加入灰名单'], 422);
}
@ -210,15 +250,17 @@ class ActivityRegistrationController extends Controller
$count = 0;
$failed = [];
foreach ($reservations as $reservation) {
if (!$user->isSuperAdmin()) {
if (! $user->isSuperAdmin()) {
$allowed = $user->venues()->where('venues.id', $reservation->venue_id)->exists();
if (!$allowed) {
if (! $allowed) {
$failed[] = ['reservation_id' => $reservation->id, 'reason' => '无场馆权限'];
continue;
}
}
if (!$reservation->visitor_phone) {
if (! $reservation->visitor_phone) {
$failed[] = ['reservation_id' => $reservation->id, 'reason' => '缺少手机号'];
continue;
}

@ -73,6 +73,8 @@ class ReservationVerifyController extends Controller
$q->whereNull('reservation_kind')
->orWhere('reservation_kind', Reservation::KIND_ACTIVITY);
});
} elseif ($cred->portal_kind === VerifyPortalCredential::KIND_TICKET_GRAB_VENUE) {
$query->where('reservation_kind', Reservation::KIND_TICKET_GRAB);
} else {
$query->where('reservation_kind', Reservation::KIND_TICKET_GRAB)
->where('ticket_grab_event_id', $cred->portal_id);
@ -94,11 +96,13 @@ class ReservationVerifyController extends Controller
if ((string) ($reservation->reservation_kind ?? '') === Reservation::KIND_TICKET_GRAB) {
abort(403, '该预约不属于本活动');
}
} else {
if ((string) $reservation->reservation_kind !== Reservation::KIND_TICKET_GRAB
|| (int) ($reservation->ticket_grab_event_id ?? 0) !== (int) $cred->portal_id) {
abort(403, '该预约不属于本抢票活动');
} elseif ($cred->portal_kind === VerifyPortalCredential::KIND_TICKET_GRAB_VENUE) {
if ((string) ($reservation->reservation_kind ?? '') !== Reservation::KIND_TICKET_GRAB) {
abort(403, '该预约不属于抢票');
}
} elseif ((string) $reservation->reservation_kind !== Reservation::KIND_TICKET_GRAB
|| (int) ($reservation->ticket_grab_event_id ?? 0) !== (int) $cred->portal_id) {
abort(403, '该预约不属于本抢票活动');
}
return;
@ -288,6 +292,11 @@ class ReservationVerifyController extends Controller
->whereHas('activityDay', function ($q3) use ($today) {
$q3->whereDate('activity_date', $today);
});
} elseif ($cred->portal_kind === VerifyPortalCredential::KIND_TICKET_GRAB_VENUE) {
$base = Reservation::query()
->where('venue_id', $cred->venue_id)
->where('reservation_kind', $tg)
->whereDate('entry_date', $today);
} else {
$base = Reservation::query()
->where('venue_id', $cred->venue_id)

@ -4,9 +4,10 @@ namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\DictItem;
use App\Support\HtmlToPlainText;
use App\Models\StudyTour;
use App\Models\Venue;
use App\Support\HtmlToPlainText;
use App\Support\VenueVerifyPortalPin;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@ -67,6 +68,8 @@ class VenueController extends Controller
$user->venues()->syncWithoutDetaching([$venue->id]);
}
VenueVerifyPortalPin::ensure($venue->fresh());
return response()->json($venue->fresh(), 201);
}
@ -389,6 +392,8 @@ class VenueController extends Controller
$venue->fill($data)->save();
VenueVerifyPortalPin::ensure($venue->fresh());
return response()->json($venue->fresh());
}
@ -402,6 +407,8 @@ class VenueController extends Controller
$venue->last_approved_snapshot = null;
$venue->save();
VenueVerifyPortalPin::ensure($venue->fresh());
return response()->json($venue->fresh());
}

@ -5,7 +5,10 @@ namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Activity;
use App\Models\TicketGrabEvent;
use App\Models\Venue;
use App\Models\VerifyPortalCredential;
use App\Support\ActivityVerifyPortalPin;
use App\Support\VenueVerifyPortalPin;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
@ -13,35 +16,11 @@ use Illuminate\Support\Facades\Hash;
class VerifyPortalAuthController extends Controller
{
/**
* 登录页展示用:根据短码或旧 portal 参数解析活动/抢票名称(无需登录)
* 历史抢票短链 ?v= 入口已废弃;统一使用与活动相同的核销页 + 6 位口令
*/
public function portalPreview(Request $request): JsonResponse
{
$code = strtolower(trim((string) $request->query('portal_code', '')));
$portalToken = trim((string) $request->query('portal_token', ''));
$activity = null;
$tg = null;
if ($code !== '') {
$activity = Activity::query()->where('verify_portal_code', $code)->first();
if (! $activity) {
$tg = TicketGrabEvent::query()->where('verify_portal_code', $code)->first();
}
} elseif ($portalToken !== '' && strlen($portalToken) >= 32) {
$activity = Activity::query()->where('verify_portal_token', $portalToken)->first();
if (! $activity) {
$tg = TicketGrabEvent::query()->where('verify_portal_token', $portalToken)->first();
}
}
if (! $activity && ! $tg) {
return response()->json(['message' => '无效的核销入口'], 404);
}
$title = $activity ? (string) $activity->title : (string) $tg->title;
return response()->json(['event_title' => $title]);
return response()->json(['message' => '请使用平台统一核销入口'], 404);
}
public function login(Request $request): JsonResponse
@ -49,66 +28,79 @@ class VerifyPortalAuthController extends Controller
$data = $request->validate([
'portal_code' => ['nullable', 'string', 'max:16'],
'portal_token' => ['nullable', 'string', 'max:64'],
'username' => ['required', 'string', 'max:64'],
'username' => ['nullable', 'string', 'max:64'],
'password' => ['required', 'string', 'max:72'],
]);
$code = strtolower(trim((string) ($data['portal_code'] ?? '')));
$portalToken = trim((string) ($data['portal_token'] ?? ''));
if ($code === '' && ($portalToken === '' || strlen($portalToken) < 32)) {
return response()->json(['message' => '请提供核销入口短码或有效入口参数'], 422);
}
$activity = null;
$tg = null;
$password = (string) ($data['password'] ?? '');
$passwordTrim = trim($password);
$usernameInput = trim((string) ($data['username'] ?? ''));
if ($code !== '') {
$activity = Activity::query()->where('verify_portal_code', $code)->first();
if (! $activity) {
$tg = TicketGrabEvent::query()->where('verify_portal_code', $code)->first();
}
} elseif ($portalToken !== '' && strlen($portalToken) >= 32) {
$activity = Activity::query()->where('verify_portal_token', $portalToken)->first();
if (! $activity) {
$tg = TicketGrabEvent::query()->where('verify_portal_token', $portalToken)->first();
if (preg_match('/^\d{6}$/', $passwordTrim)) {
if ($usernameInput !== '') {
return response()->json(['message' => '核销只需输入 6 位数字口令,无需用户名'], 422);
}
}
if ($activity) {
$kind = VerifyPortalCredential::KIND_ACTIVITY;
$portalId = (int) $activity->id;
} elseif ($tg) {
$kind = VerifyPortalCredential::KIND_TICKET_GRAB;
$portalId = (int) $tg->id;
} else {
return response()->json(['message' => '无效的核销入口'], 404);
}
$cred = VerifyPortalCredential::query()
->where('portal_kind', $kind)
->where('portal_id', $portalId)
->where('username', $data['username'])
->first();
/** @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,
]);
}
if (! $cred || ! Hash::check($data['password'], $cred->password)) {
return response()->json(['message' => '账号或密码错误'], 422);
}
/** @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,
]);
}
if (! $cred->portalAcceptsVerification()) {
return response()->json(['message' => '活动已结束,无法登录核销'], 422);
return response()->json(['message' => '密码错误'], 422);
}
$cred->tokens()->delete();
$expiresAt = now()->addMonths(6);
$plain = $cred->createToken('verify-portal', ['verify-portal'], $expiresAt)->plainTextToken;
return response()->json([
'token' => $plain,
'auth_mode' => 'verify_portal',
'portal_kind' => $kind,
'portal_id' => $portalId,
]);
'message' => '请使用后台账号用户名与密码登录,或直接输入 6 位数字核销口令(活动或抢票场馆口令)。',
], 422);
}
public function me(Request $request): JsonResponse
@ -121,22 +113,30 @@ class VerifyPortalAuthController extends Controller
if (! $cred->portalAcceptsVerification()) {
$cred->tokens()->delete();
return response()->json(['message' => '活动已结束,核销已失效'], 403);
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' => $cred->username,
'username' => $hidePinUser ? null : $cred->username,
'venue' => $cred->venue ? ['id' => $cred->venue->id, 'name' => $cred->venue->name] : null,
'event_title' => $title,
]);

@ -6,13 +6,12 @@ use App\Http\Controllers\Controller;
use App\Models\Activity;
use App\Models\TicketGrabEvent;
use App\Models\TicketGrabEventVenue;
use App\Models\VerifyPortalCredential;
use App\Models\Venue;
use App\Support\ActivityVerifyPortalPin;
use App\Support\VenueVerifyPortalPin;
use App\Support\VerifyPortalCode;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules\Password;
class VerifyPortalManageController extends Controller
{
@ -24,83 +23,32 @@ class VerifyPortalManageController extends Controller
}
VerifyPortalCode::ensureForActivity($activity);
$activity->refresh();
$rows = VerifyPortalCredential::query()
->where('portal_kind', VerifyPortalCredential::KIND_ACTIVITY)
->where('portal_id', $activity->id)
->with('venue:id,name')
->orderBy('id')
->get()
->map(fn (VerifyPortalCredential $c) => $this->credentialToRow($c));
$pin = ActivityVerifyPortalPin::ensure($activity);
return response()->json([
'verify_portal_code' => $activity->verify_portal_code,
'credentials' => $rows,
'verify_portal_pin' => $pin,
'credentials' => [],
]);
}
public function activityStore(Request $request, Activity $activity): JsonResponse
public function activityStore(Request $request, Activity $activity): void
{
$this->ensureActivityVerifyCredentialMutation($request, $activity);
$data = $request->validate([
'username' => ['required', 'string', 'max:64'],
'password' => ['required', 'string', 'min:6', 'max:72'],
'note' => ['nullable', 'string', 'max:255'],
]);
$vid = (int) $activity->venue_id;
$exists = VerifyPortalCredential::query()
->where('portal_kind', VerifyPortalCredential::KIND_ACTIVITY)
->where('portal_id', $activity->id)
->where('venue_id', $vid)
->where('username', $data['username'])
->exists();
if ($exists) {
return response()->json(['message' => '该场馆下此用户名已存在'], 422);
}
$plain = (string) $data['password'];
$c = VerifyPortalCredential::query()->create([
'portal_kind' => VerifyPortalCredential::KIND_ACTIVITY,
'portal_id' => $activity->id,
'venue_id' => $vid,
'username' => $data['username'],
'password' => Hash::make($plain),
'password_plain_enc' => Crypt::encryptString($plain),
'note' => $data['note'] ?? null,
]);
return response()->json(['id' => $c->id], 201);
abort(410, '活动核销已统一为全局核销页,仅需 6 位数字密码,无法再添加核销子账号');
}
public function activityUpdate(Request $request, Activity $activity, VerifyPortalCredential $verifyPortalCredential): JsonResponse
public function activityUpdate(Request $request, Activity $activity, \App\Models\VerifyPortalCredential $verifyPortalCredential): void
{
$this->ensureActivityVerifyCredentialMutation($request, $activity);
$this->assertCredentialBelongsActivity($verifyPortalCredential, $activity);
$data = $request->validate([
'password' => ['sometimes', 'string', 'min:6', 'max:72'],
'note' => ['sometimes', 'nullable', 'string', 'max:255'],
]);
if (array_key_exists('password', $data)) {
$plain = (string) $data['password'];
$verifyPortalCredential->password = Hash::make($plain);
$verifyPortalCredential->password_plain_enc = Crypt::encryptString($plain);
}
if (array_key_exists('note', $data)) {
$verifyPortalCredential->note = $data['note'];
}
$verifyPortalCredential->save();
return response()->json(['message' => '已更新']);
abort(410, '活动核销已统一为全局核销页与 6 位数字密码');
}
public function activityDestroy(Request $request, Activity $activity, VerifyPortalCredential $verifyPortalCredential): JsonResponse
public function activityDestroy(Request $request, Activity $activity, \App\Models\VerifyPortalCredential $verifyPortalCredential): void
{
$this->ensureActivityVerifyCredentialMutation($request, $activity);
$this->assertCredentialBelongsActivity($verifyPortalCredential, $activity);
$verifyPortalCredential->tokens()->delete();
$verifyPortalCredential->delete();
return response()->json(['message' => '已删除']);
abort(410, '活动核销已统一为全局核销页与 6 位数字密码');
}
/**
* 抢票核销与本活动场次无关:与本抢票参与场馆对齐,每场管展示其场馆级 6 位口令(与活动共用同一登录页)。
*/
public function ticketGrabShow(Request $request, TicketGrabEvent $ticketGrabEvent): JsonResponse
{
$this->ensureTicketGrabAdmin($request, $ticketGrabEvent);
@ -109,121 +57,53 @@ class VerifyPortalManageController extends Controller
}
VerifyPortalCode::ensureForTicketGrabEvent($ticketGrabEvent);
$ticketGrabEvent->refresh();
$rows = VerifyPortalCredential::query()
->where('portal_kind', VerifyPortalCredential::KIND_TICKET_GRAB)
->where('portal_id', $ticketGrabEvent->id)
->with('venue:id,name')
->orderBy('venue_id')
$venueIds = TicketGrabEventVenue::query()
->where('ticket_grab_event_id', $ticketGrabEvent->id)
->orderBy('id')
->get()
->map(fn (VerifyPortalCredential $c) => $this->credentialToRow($c));
->pluck('venue_id')
->unique()
->values();
$venues = [];
foreach ($venueIds as $vid) {
$v = Venue::query()->find((int) $vid);
if ($v === null) {
continue;
}
$pin = VenueVerifyPortalPin::ensure($v);
$venues[] = [
'venue_id' => $v->id,
'venue_name' => $v->name,
'verify_portal_pin' => $pin,
];
}
return response()->json([
'verify_portal_code' => $ticketGrabEvent->verify_portal_code,
'credentials' => $rows,
'unified_verify_notice' => '与「活动核销」相同:浏览器打开统一核销登录页后,由各场馆使用自己的 6 位数字口令进入;口令仅核销本场馆的抢票预约。',
'venues' => $venues,
]);
}
public function ticketGrabStore(Request $request, TicketGrabEvent $ticketGrabEvent): JsonResponse
public function ticketGrabStore(Request $request, TicketGrabEvent $ticketGrabEvent): void
{
$this->ensureTicketGrabAdmin($request, $ticketGrabEvent);
$data = $request->validate([
'venue_id' => ['required', 'integer'],
'username' => ['required', 'string', 'max:64'],
'password' => ['required', 'string', 'max:72', Password::min(8)->mixedCase()->symbols()],
'note' => ['nullable', 'string', 'max:255'],
]);
$vid = (int) $data['venue_id'];
$pivotOk = TicketGrabEventVenue::query()
->where('ticket_grab_event_id', $ticketGrabEvent->id)
->where('venue_id', $vid)
->exists();
abort_unless($pivotOk, 422, '场馆未参与本抢票活动');
$exists = VerifyPortalCredential::query()
->where('portal_kind', VerifyPortalCredential::KIND_TICKET_GRAB)
->where('portal_id', $ticketGrabEvent->id)
->where('venue_id', $vid)
->where('username', $data['username'])
->exists();
if ($exists) {
return response()->json(['message' => '该场馆下此用户名已存在'], 422);
}
$plain = (string) $data['password'];
$c = VerifyPortalCredential::query()->create([
'portal_kind' => VerifyPortalCredential::KIND_TICKET_GRAB,
'portal_id' => $ticketGrabEvent->id,
'venue_id' => $vid,
'username' => $data['username'],
'password' => Hash::make($plain),
'password_plain_enc' => Crypt::encryptString($plain),
'note' => $data['note'] ?? null,
]);
return response()->json(['id' => $c->id], 201);
abort(410, '抢票核销已改为场馆维度 6 位数字口令,无法再添加核销子账号');
}
public function ticketGrabUpdate(
Request $request,
TicketGrabEvent $ticketGrabEvent,
VerifyPortalCredential $verifyPortalCredential,
): JsonResponse {
$this->ensureTicketGrabAdmin($request, $ticketGrabEvent);
$this->assertCredentialBelongsTicketGrab($verifyPortalCredential, $ticketGrabEvent);
$data = $request->validate([
'password' => ['sometimes', 'string', 'max:72', Password::min(8)->mixedCase()->symbols()],
'note' => ['sometimes', 'nullable', 'string', 'max:255'],
]);
if (array_key_exists('password', $data)) {
$plain = (string) $data['password'];
$verifyPortalCredential->password = Hash::make($plain);
$verifyPortalCredential->password_plain_enc = Crypt::encryptString($plain);
}
if (array_key_exists('note', $data)) {
$verifyPortalCredential->note = $data['note'];
}
$verifyPortalCredential->save();
return response()->json(['message' => '已更新']);
\App\Models\VerifyPortalCredential $verifyPortalCredential,
): void {
abort(410, '抢票核销已改为场馆 6 位数字口令');
}
public function ticketGrabDestroy(
Request $request,
TicketGrabEvent $ticketGrabEvent,
VerifyPortalCredential $verifyPortalCredential,
): JsonResponse {
$this->ensureTicketGrabAdmin($request, $ticketGrabEvent);
$this->assertCredentialBelongsTicketGrab($verifyPortalCredential, $ticketGrabEvent);
$verifyPortalCredential->tokens()->delete();
$verifyPortalCredential->delete();
return response()->json(['message' => '已删除']);
}
/**
* @return array<string, mixed>
*/
private function credentialToRow(VerifyPortalCredential $c): array
{
$plain = null;
if ($c->password_plain_enc !== null && $c->password_plain_enc !== '') {
try {
$plain = Crypt::decryptString($c->password_plain_enc);
} catch (\Throwable) {
$plain = null;
}
}
return [
'id' => $c->id,
'venue_id' => $c->venue_id,
'venue_name' => $c->venue?->name,
'username' => $c->username,
'password_plain' => $plain,
'note' => $c->note,
'created_at' => $c->created_at?->toDateTimeString(),
];
\App\Models\VerifyPortalCredential $verifyPortalCredential,
): void {
abort(410, '抢票核销已改为场馆 6 位数字口令');
}
private function ensureActivityVenueAdmin(Request $request, Activity $activity): void
@ -232,19 +112,13 @@ class VerifyPortalManageController extends Controller
if ($user->isSuperAdmin()) {
return;
}
if ($activity->submitted_by !== null && (int) $activity->submitted_by === (int) $user->id) {
return;
}
$allowed = $user->venues()->where('venues.id', $activity->venue_id)->exists();
abort_unless($allowed, 403, '仅可操作已绑定场馆');
}
/** 场馆管理员仅可查看核销链接与账号,不可增删改凭证 */
private function ensureActivityVerifyCredentialMutation(Request $request, Activity $activity): void
{
$this->ensureActivityVenueAdmin($request, $activity);
if ($request->user()->role === 'venue_admin') {
abort(403, '场馆管理员仅可查看核销信息');
}
}
private function ensureTicketGrabAdmin(Request $request, TicketGrabEvent $e): void
{
$pivots = TicketGrabEventVenue::query()
@ -265,20 +139,4 @@ class VerifyPortalManageController extends Controller
}
}
}
private function assertCredentialBelongsActivity(VerifyPortalCredential $c, Activity $activity): void
{
abort_unless(
$c->portal_kind === VerifyPortalCredential::KIND_ACTIVITY && (int) $c->portal_id === (int) $activity->id,
404
);
}
private function assertCredentialBelongsTicketGrab(VerifyPortalCredential $c, TicketGrabEvent $e): void
{
abort_unless(
$c->portal_kind === VerifyPortalCredential::KIND_TICKET_GRAB && (int) $c->portal_id === (int) $e->id,
404
);
}
}

@ -7,9 +7,59 @@ use Illuminate\Http\Request;
trait AuthorizesActivitySubmitter
{
/**
* 超级管理员、活动创建人、或绑定该活动场馆的用户,可对活动做「场馆范围」类操作前置校验。
*/
protected function ensureVenueOrCreatorPermission(Request $request, Activity $activity): void
{
$user = $request->user();
if ($user->isSuperAdmin()) {
return;
}
if ($activity->submitted_by !== null && (int) $activity->submitted_by === (int) $user->id) {
return;
}
$allowed = $user->venues()->where('venues.id', $activity->venue_id)->exists();
abort_unless($allowed, 403, '仅可操作已绑定场馆');
}
/**
* 活动基础信息与场次:超级管理员或活动创建人可编辑。
*/
protected function authorizeActivityFullEdit(Request $request, Activity $activity): void
{
$user = $request->user();
if ($user?->isSuperAdmin()) {
return;
}
abort_unless(
$user && $activity->submitted_by !== null && (int) $activity->submitted_by === (int) $user->id,
403,
'仅活动创建者可编辑活动信息与场次'
);
}
/**
* 可查看协作信息(审核记录、场次设置等):超管、创建人、或该活动所属绑定场馆管理员。
*/
protected function authorizeActivityCollaboratorView(Request $request, Activity $activity): void
{
$user = $request->user();
if ($user?->isSuperAdmin()) {
return;
}
if ($user && $activity->submitted_by !== null && (int) $activity->submitted_by === (int) $user->id) {
return;
}
if ($user && $user->venues()->where('venues.id', $activity->venue_id)->exists()) {
return;
}
abort(403, '无权查看');
}
/**
* 花絮:超管、活动所属绑定场馆用户、或活动创建人可编辑。
* (活动所属场馆权限已由 {@see ActivityController::ensureVenuePermission} 保证。)
* (活动所属场馆权限已由 {@see ActivityController::ensureVenuePermission} 或 {@see ensureVenueOrCreatorPermission} 保证。)
*/
protected function authorizeActivityBehindScenesEdit(Request $request, Activity $activity): void
{

@ -37,6 +37,7 @@ class Activity extends Model
protected $fillable = [
'venue_id',
'verify_portal_pin',
'submitted_by',
'reservation_type',
'location',
@ -79,6 +80,13 @@ class Activity extends Model
'external_link_click_count',
];
/**
* @var list<string>
*/
protected $hidden = [
'verify_portal_pin',
];
public const AUDIT_APPROVED = 'approved';
public const AUDIT_PENDING = 'pending';
@ -166,6 +174,11 @@ class Activity extends Model
return $this->belongsTo(User::class, 'submitted_by');
}
public function auditLogs(): HasMany
{
return $this->hasMany(ActivityAuditLog::class)->orderByDesc('created_at');
}
public function reservations(): HasMany
{
return $this->hasMany(Reservation::class);

@ -0,0 +1,33 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class ActivityAuditLog extends Model
{
public const ACTION_APPROVE = 'approve';
public const ACTION_REJECT = 'reject';
/** 场馆/创建人保存活动并重新提交审核(非平台超管的 PUT update */
public const ACTION_EDIT_SUBMIT = 'edit_submit';
protected $fillable = [
'activity_id',
'admin_user_id',
'action',
'remark',
];
public function activity(): BelongsTo
{
return $this->belongsTo(Activity::class);
}
public function adminUser(): BelongsTo
{
return $this->belongsTo(User::class, 'admin_user_id');
}
}

@ -67,6 +67,10 @@ class Venue extends Model
'detail_html', 'live_people_count', 'sort', 'is_active', 'is_included_in_stats',
];
protected $hidden = [
'verify_portal_pin',
];
protected $casts = [
'is_active' => 'boolean',
'is_included_in_stats' => 'boolean',

@ -14,6 +14,9 @@ class VerifyPortalCredential extends Model
public const KIND_TICKET_GRAB = 'ticket_grab';
/** 抢票核销:按场馆 6 位口令portal_id = venue_id */
public const KIND_TICKET_GRAB_VENUE = 'ticket_grab_venue';
protected $fillable = [
'portal_kind',
'portal_id',
@ -61,6 +64,13 @@ class VerifyPortalCredential extends Model
return now()->toDateString() <= $e->end_at->toDateString();
}
if ($this->portal_kind === self::KIND_TICKET_GRAB_VENUE) {
$v = Venue::query()->find($this->portal_id);
return $v !== null
&& $v->is_active
&& $v->audit_status === Venue::AUDIT_APPROVED;
}
return false;
}

@ -0,0 +1,86 @@
<?php
namespace App\Support;
use App\Models\Activity;
use App\Models\VerifyPortalCredential;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
final class ActivityVerifyPortalPin
{
/** verify_portal_credentials 中占位用户名,核销登录仅校验 6 位数字密码并按活动发卡 */
public const CRED_USERNAME = '__pin__';
/** 随机 6 位数字口令,与场馆抢票口令一起全库唯一(含软删活动占用) */
public static function generateUnique(): string
{
return PortalSixDigitPin::generateUnique();
}
public static function syncPinCredential(Activity $activity): VerifyPortalCredential
{
$pin = trim((string) ($activity->verify_portal_pin ?? ''));
if ($pin === '' || ! preg_match('/^\d{6}$/', $pin)) {
throw new \InvalidArgumentException('活动核销口令无效');
}
/** @var VerifyPortalCredential|null $cred */
$cred = VerifyPortalCredential::query()
->where('portal_kind', VerifyPortalCredential::KIND_ACTIVITY)
->where('portal_id', $activity->id)
->where('username', self::CRED_USERNAME)
->first();
$attributes = [
'venue_id' => (int) $activity->venue_id,
'password' => Hash::make($pin),
'password_plain_enc' => Crypt::encryptString($pin),
'note' => null,
];
if ($cred !== null) {
$cred->forceFill($attributes)->save();
return $cred;
}
return VerifyPortalCredential::query()->create(array_merge([
'portal_kind' => VerifyPortalCredential::KIND_ACTIVITY,
'portal_id' => (int) $activity->id,
'username' => self::CRED_USERNAME,
], $attributes));
}
/** 补齐 activities.verify_portal_pin 占位凭证行 */
public static function ensure(Activity $activity): string
{
$activity->refresh();
$pinOut = trim((string) ($activity->verify_portal_pin ?? ''));
if ($pinOut !== '' && preg_match('/^\d{6}$/', $pinOut)) {
self::syncPinCredential($activity);
return $pinOut;
}
DB::transaction(function () use ($activity): void {
$fresh = Activity::query()->whereKey($activity->id)->lockForUpdate()->first();
if ($fresh === null) {
return;
}
$p = trim((string) ($fresh->verify_portal_pin ?? ''));
if ($p !== '' && preg_match('/^\d{6}$/', $p)) {
return;
}
$fresh->forceFill(['verify_portal_pin' => self::generateUnique()])->saveQuietly();
});
$activity->refresh();
$pinOut = trim((string) ($activity->verify_portal_pin ?? ''));
self::syncPinCredential($activity);
return $pinOut;
}
}

@ -0,0 +1,30 @@
<?php
namespace App\Support;
use App\Models\Activity;
use App\Models\Venue;
/** 活动 + 场馆核销共用 6 位数字,全库唯一(含软删活动占用) */
final class PortalSixDigitPin
{
public static function isTaken(string $pin): bool
{
$pin = trim($pin);
return Activity::withTrashed()->where('verify_portal_pin', $pin)->exists()
|| Venue::query()->where('verify_portal_pin', $pin)->exists();
}
public static function generateUnique(): string
{
for ($n = 0; $n < 500; $n++) {
$pin = sprintf('%06d', random_int(0, 999_999));
if (! self::isTaken($pin)) {
return $pin;
}
}
return sprintf('%06d', random_int(0, 999_999));
}
}

@ -0,0 +1,81 @@
<?php
namespace App\Support;
use App\Models\Venue;
use App\Models\VerifyPortalCredential;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
/** 抢票核销:场馆维度 6 位口令(与活动共用同一核销入口页);凭证 kind = ticket_grab_venue */
final class VenueVerifyPortalPin
{
public const CRED_USERNAME = '__tg_pin__';
public static function syncPinCredential(Venue $venue): VerifyPortalCredential
{
$pin = trim((string) ($venue->verify_portal_pin ?? ''));
if ($pin === '' || ! preg_match('/^\d{6}$/', $pin)) {
throw new \InvalidArgumentException('场馆抢票核销口令无效');
}
$vid = (int) $venue->id;
/** @var VerifyPortalCredential|null $cred */
$cred = VerifyPortalCredential::query()
->where('portal_kind', VerifyPortalCredential::KIND_TICKET_GRAB_VENUE)
->where('portal_id', $vid)
->where('username', self::CRED_USERNAME)
->first();
$attributes = [
'venue_id' => $vid,
'password' => Hash::make($pin),
'password_plain_enc' => Crypt::encryptString($pin),
'note' => null,
];
if ($cred !== null) {
$cred->forceFill($attributes)->save();
return $cred;
}
return VerifyPortalCredential::query()->create(array_merge([
'portal_kind' => VerifyPortalCredential::KIND_TICKET_GRAB_VENUE,
'portal_id' => $vid,
'username' => self::CRED_USERNAME,
], $attributes));
}
public static function ensure(Venue $venue): string
{
$venue->refresh();
$pinOut = trim((string) ($venue->verify_portal_pin ?? ''));
if ($pinOut !== '' && preg_match('/^\d{6}$/', $pinOut)) {
self::syncPinCredential($venue);
return $pinOut;
}
DB::transaction(function () use ($venue): void {
$fresh = Venue::query()->whereKey($venue->id)->lockForUpdate()->first();
if ($fresh === null) {
return;
}
$p = trim((string) ($fresh->verify_portal_pin ?? ''));
if ($p !== '' && preg_match('/^\d{6}$/', $p)) {
return;
}
$fresh->forceFill(['verify_portal_pin' => PortalSixDigitPin::generateUnique()])->saveQuietly();
});
$venue->refresh();
$pinOut = trim((string) ($venue->verify_portal_pin ?? ''));
self::syncPinCredential($venue);
return $pinOut;
}
}

@ -0,0 +1,26 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('activity_audit_logs', function (Blueprint $table) {
$table->id();
$table->foreignId('activity_id')->constrained('activities')->cascadeOnDelete();
$table->foreignId('admin_user_id')->nullable()->constrained('users')->nullOnDelete();
$table->string('action', 20);
$table->text('remark')->nullable();
$table->timestamps();
$table->index(['activity_id', 'created_at']);
});
}
public function down(): void
{
Schema::dropIfExists('activity_audit_logs');
}
};

@ -0,0 +1,71 @@
<?php
use App\Models\Activity;
use App\Models\VerifyPortalCredential;
use App\Support\ActivityVerifyPortalPin;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('activities', function (Blueprint $table) {
$table->string('verify_portal_pin', 6)->nullable()->unique()->after('verify_portal_code');
});
foreach (
VerifyPortalCredential::query()
->where('portal_kind', VerifyPortalCredential::KIND_ACTIVITY)
->where('username', '!=', ActivityVerifyPortalPin::CRED_USERNAME)
->cursor() as $c
) {
$c->tokens()->delete();
$c->delete();
}
Activity::query()
->orderBy('id')
->chunkById(80, function ($activities) {
foreach ($activities as $activity) {
/** @var Activity $activity */
try {
if ($activity->verify_portal_pin === null || trim((string) $activity->verify_portal_pin) === '') {
$pin = ActivityVerifyPortalPin::generateUnique();
DB::table('activities')->where('id', $activity->id)->update([
'verify_portal_pin' => $pin,
'updated_at' => now(),
]);
$activity->verify_portal_pin = $pin;
}
$fresh = Activity::query()->find($activity->id);
if ($fresh !== null) {
ActivityVerifyPortalPin::syncPinCredential($fresh);
}
} catch (\Throwable) {
// ensure() runs on admin open
}
}
});
}
public function down(): void
{
foreach (
VerifyPortalCredential::query()
->where('portal_kind', VerifyPortalCredential::KIND_ACTIVITY)
->where('username', ActivityVerifyPortalPin::CRED_USERNAME)
->cursor() as $c
) {
$c->tokens()->delete();
$c->delete();
}
Schema::table('activities', function (Blueprint $table) {
$table->dropUnique(['verify_portal_pin']);
$table->dropColumn('verify_portal_pin');
});
}
};

@ -0,0 +1,75 @@
<?php
use App\Models\Venue;
use App\Models\VerifyPortalCredential;
use App\Support\PortalSixDigitPin;
use App\Support\VenueVerifyPortalPin;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('venues', function (Blueprint $table) {
$table->string('verify_portal_pin', 6)->nullable()->unique();
});
Venue::query()
->orderBy('id')
->chunkById(80, function ($venues) {
foreach ($venues as $venue) {
/** @var Venue $venue */
if ($venue->verify_portal_pin !== null && trim((string) $venue->verify_portal_pin) !== '') {
continue;
}
DB::table('venues')->where('id', $venue->id)->update([
'verify_portal_pin' => PortalSixDigitPin::generateUnique(),
'updated_at' => now(),
]);
}
});
foreach (
VerifyPortalCredential::query()->where('portal_kind', VerifyPortalCredential::KIND_TICKET_GRAB)->cursor() as $c
) {
$c->tokens()->delete();
$c->delete();
}
Venue::query()
->orderBy('id')
->chunkById(80, function ($venues) {
foreach ($venues as $venue) {
/** @var Venue $venue */
$fresh = Venue::query()->find($venue->id);
if ($fresh !== null) {
try {
VenueVerifyPortalPin::syncPinCredential($fresh);
} catch (\Throwable) {
// sync on next ensure
}
}
}
});
}
public function down(): void
{
foreach (
VerifyPortalCredential::query()
->where('portal_kind', VerifyPortalCredential::KIND_TICKET_GRAB_VENUE)
->cursor() as $c
) {
$c->tokens()->delete();
$c->delete();
}
Schema::table('venues', function (Blueprint $table) {
$table->dropUnique(['verify_portal_pin']);
$table->dropColumn('verify_portal_pin');
});
}
};

@ -1 +0,0 @@
.activity-address-coord-row[data-v-37e0ad7b]{flex-wrap:wrap;align-items:center;gap:12px;width:100%;display:flex}.activity-address-coord-row__address[data-v-37e0ad7b]{flex:45%;min-width:320px;max-width:100%}.activity-address-coord-row__lng[data-v-37e0ad7b],.activity-address-coord-row__lat[data-v-37e0ad7b]{flex:180px;width:200px;min-width:180px}.activity-address-coord-row__map[data-v-37e0ad7b]{flex-shrink:0}.activity-cover-carousel-wrap[data-v-37e0ad7b]{flex-wrap:wrap;align-items:flex-start;gap:20px;width:100%;display:flex}.activity-cover-carousel-row__col[data-v-37e0ad7b]{flex:320px;min-width:min(100%,320px)}.activity-cover-carousel-row__sub[data-v-37e0ad7b]{color:var(--color-text-1);margin-bottom:8px;font-weight:500}.activity-cover-thumb[data-v-37e0ad7b]{object-fit:cover;cursor:zoom-in;border:1px solid #e5e6eb;border-radius:4px;width:120px;height:70px}.activity-gallery-grid[data-v-37e0ad7b]{flex-wrap:wrap;align-items:flex-start;gap:12px;width:100%;display:flex}.activity-gallery-item[data-v-37e0ad7b]{flex-direction:column;align-items:flex-start;gap:8px;display:flex}.activity-gallery-thumb[data-v-37e0ad7b]{object-fit:cover;cursor:zoom-in;border:1px solid #e5e6eb;border-radius:4px;width:120px;height:70px}.activity-gallery-thumb--video[data-v-37e0ad7b]{display:block}.activity-form-tags[data-v-37e0ad7b]{max-width:520px}.activity-form-tags__line[data-v-37e0ad7b]{flex-flow:row;align-items:center;gap:8px;width:100%;display:flex}.activity-form-tags__input[data-v-37e0ad7b]{flex:auto;min-width:0}.activity-form-tags__input[data-v-37e0ad7b] .arco-input-wrapper{width:100%}.activity-form-tags__save[data-v-37e0ad7b]{flex-shrink:0}.activity-form-tags__chips[data-v-37e0ad7b]{flex-wrap:wrap;align-items:center;gap:8px;margin-top:8px;display:flex}.activity-form-tags__empty[data-v-37e0ad7b]{color:#86909c;font-size:12px}.activity-form-tags__chips--readonly[data-v-37e0ad7b]{margin-top:0}.activity-form-tags__chips--inline[data-v-37e0ad7b]{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.activity-audit-inline[data-v-37e0ad7b]{grid-template-columns:repeat(3,minmax(0,1fr));gap:10px 16px;padding-bottom:4px;display:grid}.activity-audit-inline-row[data-v-37e0ad7b]{align-items:flex-start;gap:12px;min-width:0;font-size:14px;line-height:1.5715;display:flex}.activity-audit-inline-row--tags[data-v-37e0ad7b]{align-items:center}.activity-audit-inline-label[data-v-37e0ad7b]{color:var(--color-text-3);text-align:right;flex:0 0 74px}.activity-audit-inline-value[data-v-37e0ad7b]{min-width:0;color:var(--color-text-1);word-break:break-word;flex:1}.activity-audit-stack[data-v-37e0ad7b]{margin-top:20px}.activity-audit-stack__label[data-v-37e0ad7b]{color:var(--color-text-1);margin-bottom:8px;font-size:14px;font-weight:500}.activity-audit-stack__body[data-v-37e0ad7b]{min-width:0}@media (width<=1400px){.activity-audit-inline[data-v-37e0ad7b]{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (width<=980px){.activity-audit-inline[data-v-37e0ad7b]{grid-template-columns:minmax(0,1fr)}}.activity-audit-static-text[data-v-37e0ad7b]{color:var(--color-text-1);word-break:break-word;font-size:14px;line-height:1.5715}.activity-audit-static-text--fill[data-v-37e0ad7b]{border:1px solid var(--color-neutral-3);border-radius:var(--border-radius-small);background:var(--color-fill-2);box-sizing:border-box;align-items:center;min-height:32px;padding:4px 11px;display:flex}.activity-audit-static-coord[data-v-37e0ad7b]{border:1px solid var(--color-neutral-3);border-radius:var(--border-radius-small);background:var(--color-fill-2);box-sizing:border-box;min-height:32px;color:var(--color-text-2);font-variant-numeric:tabular-nums;align-items:center;padding:4px 11px;font-size:14px;line-height:1.5715;display:flex}.activity-audit-muted[data-v-37e0ad7b]{color:var(--color-text-3);font-size:13px}.activity-audit-break[data-v-37e0ad7b]{word-break:break-word}.activity-audit-rich[data-v-37e0ad7b]{color:var(--color-text-1);background:#fafafa;border:1px solid #e5e6eb;border-radius:8px;max-height:380px;padding:12px;font-size:13px;line-height:1.7;overflow-y:auto}.activity-audit-rich[data-v-37e0ad7b] img{vertical-align:top;max-width:100%;height:auto}.activity-audit-rich[data-v-37e0ad7b] video{max-width:100%}.bts-preview-grid[data-v-37e0ad7b]{flex-wrap:wrap;gap:16px;width:100%;display:flex}.bts-preview-item[data-v-37e0ad7b]{box-sizing:border-box;flex:none;width:220px}.bts-preview-img[data-v-37e0ad7b]{object-fit:cover;cursor:zoom-in;border:1px solid #e5e6eb;border-radius:8px;width:220px;height:220px;display:block}.bts-preview-actions[data-v-37e0ad7b]{flex-flow:row;align-items:center;gap:8px;width:100%;margin-top:8px;display:flex}.bts-preview-actions[data-v-37e0ad7b] .bts-act-btn.arco-btn-size-mini{flex:1 1 0;min-width:0;padding-left:6px;padding-right:6px}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +1 @@
import{n as e}from"./axios-CiYFffbI.js";import{I as t,N as n,V as r,Y as i,_ as a,d as o,it as s,kt as c,nt as l,u,ut as d,v as f,y as p}from"./runtime-core.esm-bundler-CnFWH3R5.js";import{n as m}from"./http-LCi9aT1G.js";import{u as h}from"./index-B-4Rg8Jl.js";import{t as g}from"./listTableRowIndex-Bl-nc9Qt.js";import{t as _}from"./datetime-DLy52ZIc.js";var v={class:`audit-api-endpoint`},y=1280,b=h(p({__name:`AuditLogs`,setup(p){let h=s(!1),b=s([]),x=l({current:1,pageSize:20,total:0}),S=l({keyword:``,method:`all`,status_code:void 0,dateRange:[]});async function C(){h.value=!0;try{let{data:e}=await m.get(`/audit-logs`,{params:{keyword:S.keyword||void 0,method:S.method,status_code:S.status_code||void 0,start_date:S.dateRange?.[0]||void 0,end_date:S.dateRange?.[1]||void 0,page:x.current,page_size:x.pageSize}});b.value=e.data,x.total=e.total}catch(t){e.error(t?.response?.data?.message??`加载操作日志失败`)}finally{h.value=!1}}function w(){x.current=1,C()}function T(e){x.current=e,C()}function E(e){return e.operation_summary&&String(e.operation_summary).trim()!==``?e.operation_summary:e.action&&String(e.action).trim()!==``?e.action:``}function D(e){let t=(e.method||``).toUpperCase()||``,n=(e.path||``).trim();return!n||n===`/`?t+``:(n.startsWith(`/`)||(n=`/`+n),`${t} ${n}`)}return n(C),(e,n)=>{let s=r(`a-alert`),l=r(`a-input`),p=r(`a-option`),m=r(`a-select`),C=r(`a-input-number`),O=r(`a-range-picker`),k=r(`a-button`),A=r(`a-space`),j=r(`a-table-column`),M=r(`a-table`),N=r(`a-card`);return t(),o(N,{title:`用户与权限 / 操作日志`},{default:i(()=>[f(s,{type:`info`,style:{"margin-bottom":`12px`},closable:``},{default:i(()=>[...n[4]||=[a(` 此处为「操作日志」(写操作审计)。系统设置里的「系统日志」页面用于查看服务器 Laravel 日志文件,不是本页。列表不包含 GET 类查询请求。 `,-1)]]),_:1}),f(A,{wrap:``,size:12,style:{"margin-bottom":`12px`}},{default:i(()=>[f(l,{modelValue:S.keyword,"onUpdate:modelValue":n[0]||=e=>S.keyword=e,placeholder:`操作人 / 操作项`,"allow-clear":``,style:{width:`240px`}},null,8,[`modelValue`]),f(m,{modelValue:S.method,"onUpdate:modelValue":n[1]||=e=>S.method=e,style:{width:`120px`}},{default:i(()=>[f(p,{value:`all`},{default:i(()=>[...n[5]||=[a(`全部方法`,-1)]]),_:1}),f(p,{value:`POST`},{default:i(()=>[...n[6]||=[a(`POST`,-1)]]),_:1}),f(p,{value:`PUT`},{default:i(()=>[...n[7]||=[a(`PUT`,-1)]]),_:1}),f(p,{value:`PATCH`},{default:i(()=>[...n[8]||=[a(`PATCH`,-1)]]),_:1}),f(p,{value:`DELETE`},{default:i(()=>[...n[9]||=[a(`DELETE`,-1)]]),_:1})]),_:1},8,[`modelValue`]),f(C,{modelValue:S.status_code,"onUpdate:modelValue":n[2]||=e=>S.status_code=e,min:100,max:599,placeholder:`状态码`,style:{width:`120px`}},null,8,[`modelValue`]),f(O,{modelValue:S.dateRange,"onUpdate:modelValue":n[3]||=e=>S.dateRange=e,style:{width:`260px`}},null,8,[`modelValue`]),f(k,{type:`primary`,onClick:w},{default:i(()=>[...n[10]||=[a(`查询`,-1)]]),_:1})]),_:1}),f(M,{class:`list-data-table`,scroll:{x:y},data:b.value,loading:h.value,"row-key":`id`,pagination:{current:x.current,pageSize:x.pageSize,total:x.total,showTotal:!0},onPageChange:T},{columns:i(()=>[f(j,{title:``,width:52,ellipsis:!0,tooltip:!0},{cell:i(({rowIndex:e})=>[a(c(d(g)(e,x.current,x.pageSize)),1)]),_:1}),f(j,{title:`操作人`,"data-index":`username`,width:140,ellipsis:!0,tooltip:!0},{cell:i(({record:e})=>[a(c(e.username||``),1)]),_:1}),f(j,{title:`操作时间`,width:178},{cell:i(({record:e})=>[a(c(d(_)(e.created_at)),1)]),_:1}),f(j,{title:`接口`,width:320,ellipsis:!0,tooltip:!0},{cell:i(({record:e})=>[u(`span`,v,c(D(e)),1)]),_:1}),f(j,{title:`操作项`,"min-width":320,ellipsis:!0,tooltip:!0},{cell:i(({record:e})=>[a(c(E(e)),1)]),_:1})]),_:1},8,[`scroll`,`data`,`loading`,`pagination`])]),_:1})}}}),[[`__scopeId`,`data-v-f4d2ff07`]]);export{b as default};
import{n as e}from"./axios-CiYFffbI.js";import{I as t,N as n,V as r,Y as i,_ as a,d as o,it as s,kt as c,nt as l,u,ut as d,v as f,y as p}from"./runtime-core.esm-bundler-CnFWH3R5.js";import{n as m}from"./http-LCi9aT1G.js";import{u as h}from"./index-DHqNSBjF.js";import{t as g}from"./listTableRowIndex-Bl-nc9Qt.js";import{t as _}from"./datetime-DLy52ZIc.js";var v={class:`audit-api-endpoint`},y=1280,b=h(p({__name:`AuditLogs`,setup(p){let h=s(!1),b=s([]),x=l({current:1,pageSize:20,total:0}),S=l({keyword:``,method:`all`,status_code:void 0,dateRange:[]});async function C(){h.value=!0;try{let{data:e}=await m.get(`/audit-logs`,{params:{keyword:S.keyword||void 0,method:S.method,status_code:S.status_code||void 0,start_date:S.dateRange?.[0]||void 0,end_date:S.dateRange?.[1]||void 0,page:x.current,page_size:x.pageSize}});b.value=e.data,x.total=e.total}catch(t){e.error(t?.response?.data?.message??`加载操作日志失败`)}finally{h.value=!1}}function w(){x.current=1,C()}function T(e){x.current=e,C()}function E(e){return e.operation_summary&&String(e.operation_summary).trim()!==``?e.operation_summary:e.action&&String(e.action).trim()!==``?e.action:``}function D(e){let t=(e.method||``).toUpperCase()||``,n=(e.path||``).trim();return!n||n===`/`?t+``:(n.startsWith(`/`)||(n=`/`+n),`${t} ${n}`)}return n(C),(e,n)=>{let s=r(`a-alert`),l=r(`a-input`),p=r(`a-option`),m=r(`a-select`),C=r(`a-input-number`),O=r(`a-range-picker`),k=r(`a-button`),A=r(`a-space`),j=r(`a-table-column`),M=r(`a-table`),N=r(`a-card`);return t(),o(N,{title:`用户与权限 / 操作日志`},{default:i(()=>[f(s,{type:`info`,style:{"margin-bottom":`12px`},closable:``},{default:i(()=>[...n[4]||=[a(` 此处为「操作日志」(写操作审计)。系统设置里的「系统日志」页面用于查看服务器 Laravel 日志文件,不是本页。列表不包含 GET 类查询请求。 `,-1)]]),_:1}),f(A,{wrap:``,size:12,style:{"margin-bottom":`12px`}},{default:i(()=>[f(l,{modelValue:S.keyword,"onUpdate:modelValue":n[0]||=e=>S.keyword=e,placeholder:`操作人 / 操作项`,"allow-clear":``,style:{width:`240px`}},null,8,[`modelValue`]),f(m,{modelValue:S.method,"onUpdate:modelValue":n[1]||=e=>S.method=e,style:{width:`120px`}},{default:i(()=>[f(p,{value:`all`},{default:i(()=>[...n[5]||=[a(`全部方法`,-1)]]),_:1}),f(p,{value:`POST`},{default:i(()=>[...n[6]||=[a(`POST`,-1)]]),_:1}),f(p,{value:`PUT`},{default:i(()=>[...n[7]||=[a(`PUT`,-1)]]),_:1}),f(p,{value:`PATCH`},{default:i(()=>[...n[8]||=[a(`PATCH`,-1)]]),_:1}),f(p,{value:`DELETE`},{default:i(()=>[...n[9]||=[a(`DELETE`,-1)]]),_:1})]),_:1},8,[`modelValue`]),f(C,{modelValue:S.status_code,"onUpdate:modelValue":n[2]||=e=>S.status_code=e,min:100,max:599,placeholder:`状态码`,style:{width:`120px`}},null,8,[`modelValue`]),f(O,{modelValue:S.dateRange,"onUpdate:modelValue":n[3]||=e=>S.dateRange=e,style:{width:`260px`}},null,8,[`modelValue`]),f(k,{type:`primary`,onClick:w},{default:i(()=>[...n[10]||=[a(`查询`,-1)]]),_:1})]),_:1}),f(M,{class:`list-data-table`,scroll:{x:y},data:b.value,loading:h.value,"row-key":`id`,pagination:{current:x.current,pageSize:x.pageSize,total:x.total,showTotal:!0},onPageChange:T},{columns:i(()=>[f(j,{title:``,width:52,ellipsis:!0,tooltip:!0},{cell:i(({rowIndex:e})=>[a(c(d(g)(e,x.current,x.pageSize)),1)]),_:1}),f(j,{title:`操作人`,"data-index":`username`,width:140,ellipsis:!0,tooltip:!0},{cell:i(({record:e})=>[a(c(e.username||``),1)]),_:1}),f(j,{title:`操作时间`,width:178},{cell:i(({record:e})=>[a(c(d(_)(e.created_at)),1)]),_:1}),f(j,{title:`接口`,width:320,ellipsis:!0,tooltip:!0},{cell:i(({record:e})=>[u(`span`,v,c(D(e)),1)]),_:1}),f(j,{title:`操作项`,"min-width":320,ellipsis:!0,tooltip:!0},{cell:i(({record:e})=>[a(c(E(e)),1)]),_:1})]),_:1},8,[`scroll`,`data`,`loading`,`pagination`])]),_:1})}}}),[[`__scopeId`,`data-v-f4d2ff07`]]);export{b as default};

@ -1,2 +1,2 @@
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/dynamicAdminRoutes-Bfu9BUwK.js","assets/dynamicAdminRoutes-Bp7nHMfT.js","assets/preload-helper-BIjWqNH5.js","assets/http-LCi9aT1G.js","assets/axios-CiYFffbI.js","assets/runtime-core.esm-bundler-CnFWH3R5.js"])))=>i.map(i=>d[i]);
import{n as e}from"./axios-CiYFffbI.js";import{I as t,V as n,Y as r,_ as i,it as a,nt as o,p as s,v as c,y as l}from"./runtime-core.esm-bundler-CnFWH3R5.js";import{n as u,t as d}from"./http-LCi9aT1G.js";import{t as f}from"./preload-helper-BIjWqNH5.js";import{c as p,s as m}from"./index-B-4Rg8Jl.js";var h={style:{height:`100vh`,display:`grid`,"place-items":`center`,background:`var(--color-fill-2)`}},g=l({__name:`Login`,setup(l){let g=p(),_=m(),v=a(!1),y=o({username:`admin`,password:`admin123456`});async function b(){v.value=!0;try{let{data:t}=await u.post(`/auth/login`,y);localStorage.setItem(d,t.token),e.success(`登录成功`);let{getFirstMenuPath:n}=await f(async()=>{let{getFirstMenuPath:e}=await import(`./dynamicAdminRoutes-Bfu9BUwK.js`);return{getFirstMenuPath:e}},__vite__mapDeps([0,1,2,3,4,5])),r=typeof _.query.redirect==`string`?_.query.redirect.trim():``,i=r&&r.startsWith(`/`)&&!r.startsWith(`//`)?r:await n();g.replace(i)}catch(t){e.error(t?.response?.data?.message??`登录失败`)}finally{v.value=!1}}return(e,a)=>{let o=n(`a-input`),l=n(`a-form-item`),u=n(`a-input-password`),d=n(`a-button`),f=n(`a-form`),p=n(`a-card`);return t(),s(`div`,h,[c(p,{title:`苏州市科普场馆地图后台管理系统登录`,style:{width:`380px`}},{default:r(()=>[c(f,{model:y,layout:`vertical`,onSubmitSuccess:b},{default:r(()=>[c(l,{field:`username`,label:`用户名`},{default:r(()=>[c(o,{modelValue:y.username,"onUpdate:modelValue":a[0]||=e=>y.username=e,placeholder:`请输入用户名`},null,8,[`modelValue`])]),_:1}),c(l,{field:`password`,label:`密码`},{default:r(()=>[c(u,{modelValue:y.password,"onUpdate:modelValue":a[1]||=e=>y.password=e,placeholder:`请输入密码`},null,8,[`modelValue`])]),_:1}),c(d,{type:`primary`,long:``,loading:v.value,onClick:b},{default:r(()=>[...a[2]||=[i(`登录`,-1)]]),_:1},8,[`loading`])]),_:1},8,[`model`])]),_:1})])}}});export{g as default};
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/dynamicAdminRoutes-6nJxD7Xt.js","assets/dynamicAdminRoutes-BAMeDyVx.js","assets/preload-helper-BIjWqNH5.js","assets/http-LCi9aT1G.js","assets/axios-CiYFffbI.js","assets/runtime-core.esm-bundler-CnFWH3R5.js"])))=>i.map(i=>d[i]);
import{n as e}from"./axios-CiYFffbI.js";import{I as t,V as n,Y as r,_ as i,it as a,nt as o,p as s,v as c,y as l}from"./runtime-core.esm-bundler-CnFWH3R5.js";import{n as u,t as d}from"./http-LCi9aT1G.js";import{t as f}from"./preload-helper-BIjWqNH5.js";import{c as p,s as m}from"./index-DHqNSBjF.js";var h={style:{height:`100vh`,display:`grid`,"place-items":`center`,background:`var(--color-fill-2)`}},g=l({__name:`Login`,setup(l){let g=p(),_=m(),v=a(!1),y=o({username:`admin`,password:`admin123456`});async function b(){v.value=!0;try{let{data:t}=await u.post(`/auth/login`,y);localStorage.setItem(d,t.token),e.success(`登录成功`);let{getFirstMenuPath:n}=await f(async()=>{let{getFirstMenuPath:e}=await import(`./dynamicAdminRoutes-6nJxD7Xt.js`);return{getFirstMenuPath:e}},__vite__mapDeps([0,1,2,3,4,5])),r=typeof _.query.redirect==`string`?_.query.redirect.trim():``,i=r&&r.startsWith(`/`)&&!r.startsWith(`//`)?r:await n();g.replace(i)}catch(t){e.error(t?.response?.data?.message??`登录失败`)}finally{v.value=!1}}return(e,a)=>{let o=n(`a-input`),l=n(`a-form-item`),u=n(`a-input-password`),d=n(`a-button`),f=n(`a-form`),p=n(`a-card`);return t(),s(`div`,h,[c(p,{title:`苏州市科普场馆地图后台管理系统登录`,style:{width:`380px`}},{default:r(()=>[c(f,{model:y,layout:`vertical`,onSubmitSuccess:b},{default:r(()=>[c(l,{field:`username`,label:`用户名`},{default:r(()=>[c(o,{modelValue:y.username,"onUpdate:modelValue":a[0]||=e=>y.username=e,placeholder:`请输入用户名`},null,8,[`modelValue`])]),_:1}),c(l,{field:`password`,label:`密码`},{default:r(()=>[c(u,{modelValue:y.password,"onUpdate:modelValue":a[1]||=e=>y.password=e,placeholder:`请输入密码`},null,8,[`modelValue`])]),_:1}),c(d,{type:`primary`,long:``,loading:v.value,onClick:b},{default:r(()=>[...a[2]||=[i(`登录`,-1)]]),_:1},8,[`loading`])]),_:1},8,[`model`])]),_:1})])}}});export{g as default};

@ -1 +1 @@
import{I as e,V as t,Y as n,_ as r,d as i,v as a}from"./runtime-core.esm-bundler-CnFWH3R5.js";import{u as o}from"./index-B-4Rg8Jl.js";var s={};function c(o,s){let c=t(`a-alert`),l=t(`a-descriptions-item`),u=t(`a-descriptions`),d=t(`a-card`);return e(),i(d,{title:`系统设置 / 地图与第三方配置`},{default:n(()=>[a(c,{type:`info`,style:{"margin-bottom":`12px`}},{default:n(()=>[...s[0]||=[r(` 当前后台场馆地图选点已使用腾讯地图,坐标统一为 GCJ-02火星坐标系`,-1)]]),_:1}),a(u,{column:1,bordered:``},{default:n(()=>[a(l,{label:`前端地图Key`},{default:n(()=>[...s[1]||=[r(" 在 `code/szkp-map-web/.env` 配置 `VITE_TENCENT_MAP_KEY=你的腾讯地图JS_KEY` ",-1)]]),_:1}),a(l,{label:`地图外链 referer`},{default:n(()=>[...s[2]||=[r(" 在 `code/szkp-map-web/.env` 配置 `VITE_TENCENT_MAP_REFERER=你的应用标识` ",-1)]]),_:1}),a(l,{label:`后端服务Key`},{default:n(()=>[...s[3]||=[r(" 在 `code/szkp-map-service/.env` 配置 `TENCENT_MAP_SERVER_KEY=你的腾讯地图WebService_KEY` ",-1)]]),_:1})]),_:1})]),_:1})}var l=o(s,[[`render`,c]]);export{l as default};
import{I as e,V as t,Y as n,_ as r,d as i,v as a}from"./runtime-core.esm-bundler-CnFWH3R5.js";import{u as o}from"./index-DHqNSBjF.js";var s={};function c(o,s){let c=t(`a-alert`),l=t(`a-descriptions-item`),u=t(`a-descriptions`),d=t(`a-card`);return e(),i(d,{title:`系统设置 / 地图与第三方配置`},{default:n(()=>[a(c,{type:`info`,style:{"margin-bottom":`12px`}},{default:n(()=>[...s[0]||=[r(` 当前后台场馆地图选点已使用腾讯地图,坐标统一为 GCJ-02火星坐标系`,-1)]]),_:1}),a(u,{column:1,bordered:``},{default:n(()=>[a(l,{label:`前端地图Key`},{default:n(()=>[...s[1]||=[r(" 在 `code/szkp-map-web/.env` 配置 `VITE_TENCENT_MAP_KEY=你的腾讯地图JS_KEY` ",-1)]]),_:1}),a(l,{label:`地图外链 referer`},{default:n(()=>[...s[2]||=[r(" 在 `code/szkp-map-web/.env` 配置 `VITE_TENCENT_MAP_REFERER=你的应用标识` ",-1)]]),_:1}),a(l,{label:`后端服务Key`},{default:n(()=>[...s[3]||=[r(" 在 `code/szkp-map-service/.env` 配置 `TENCENT_MAP_SERVER_KEY=你的腾讯地图WebService_KEY` ",-1)]]),_:1})]),_:1})]),_:1})}var l=o(s,[[`render`,c]]);export{l as default};

File diff suppressed because one or more lines are too long

@ -1 +0,0 @@
.reg-toolbar[data-v-57fca2b5]{box-sizing:border-box;width:100%;max-width:100%;margin-bottom:12px}.reg-export-bar[data-v-57fca2b5]{box-sizing:border-box;grid-template-columns:130px minmax(0,1fr) auto;align-items:start;gap:12px;width:100%;margin-top:12px;display:grid}.reg-export-scope[data-v-57fca2b5]{width:130px}.reg-export-fields[data-v-57fca2b5]{width:100%;min-width:0}.reg-export-fields[data-v-57fca2b5] .arco-select-view{max-width:100%}.reg-export-btn[data-v-57fca2b5]{justify-self:start}@media (width<=720px){.reg-export-bar[data-v-57fca2b5]{grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"scope btn""fields fields"}.reg-export-scope[data-v-57fca2b5]{grid-area:scope}.reg-export-fields[data-v-57fca2b5]{grid-area:fields}.reg-export-btn[data-v-57fca2b5]{grid-area:btn;justify-self:end}}.registrations-table[data-v-57fca2b5] .arco-table-td .arco-table-cell{white-space:normal;word-break:break-word}.registrations-table[data-v-57fca2b5] .arco-table-text-ellipsis{white-space:nowrap}

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
.reg-toolbar[data-v-78924321]{box-sizing:border-box;width:100%;max-width:100%;margin-bottom:12px}.reg-export-bar[data-v-78924321]{box-sizing:border-box;grid-template-columns:130px minmax(0,1fr) auto;align-items:start;gap:12px;width:100%;margin-top:12px;display:grid}.reg-export-scope[data-v-78924321]{width:130px}.reg-export-fields[data-v-78924321]{width:100%;min-width:0}.reg-export-fields[data-v-78924321] .arco-select-view{max-width:100%}.reg-export-btn[data-v-78924321]{justify-self:start}@media (width<=720px){.reg-export-bar[data-v-78924321]{grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"scope btn""fields fields"}.reg-export-scope[data-v-78924321]{grid-area:scope}.reg-export-fields[data-v-78924321]{grid-area:fields}.reg-export-btn[data-v-78924321]{grid-area:btn;justify-self:end}}.registrations-table[data-v-78924321] .arco-table-td .arco-table-cell{white-space:normal;word-break:break-word}.registrations-table[data-v-78924321] .arco-table-text-ellipsis{white-space:nowrap}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,2 +1,2 @@
import{n as e}from"./axios-CiYFffbI.js";import{I as t,N as n,O as r,V as i,Y as a,_ as o,d as s,f as c,i as l,it as u,kt as d,l as f,p,q as m,u as h,ut as g,v as _,y as v,z as y}from"./runtime-core.esm-bundler-CnFWH3R5.js";import{n as b}from"./http-LCi9aT1G.js";import{u as x}from"./index-B-4Rg8Jl.js";import{t as S}from"./datetime-DLy52ZIc.js";var C={key:0,class:`system-logs-pre`},w={key:1,class:`system-logs-empty`},T=x(v({__name:`SystemLogs`,setup(v){let x=u(!1),T=u(``),E=u(400),D=u(``),O=u([]),k=u([]),A=u(null),j=u(null),M=u(!1),N=f(()=>{let e=T.value.trim().toLowerCase();return e?k.value.filter(t=>t.toLowerCase().includes(e)):k.value});function P(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(2)} MB`}async function F(){await r();let e=j.value;e&&(e.scrollTop=e.scrollHeight)}async function I(){x.value=!0,A.value=null;try{let{data:e}=await b.get(`/system-logs`,{params:{file:D.value||void 0,lines:E.value}});O.value=e.files??[],M.value=!0,D.value=e.file??``,await r(),M.value=!1,k.value=e.lines??[],A.value=e.error??null,await F()}catch(t){e.error(t?.response?.data?.message??`加载系统日志失败`),k.value=[],M.value=!1}finally{x.value=!1}}return m(D,()=>{M.value||I()}),n(I),(e,n)=>{let r=i(`a-alert`),u=i(`a-option`),f=i(`a-select`),m=i(`a-input-number`),v=i(`a-input`),b=i(`a-button`),k=i(`a-space`),M=i(`a-spin`),F=i(`a-card`);return t(),s(F,{title:`系统设置 / 系统日志`},{default:a(()=>[_(r,{type:`warning`,style:{"margin-bottom":`12px`}},{default:a(()=>[...n[3]||=[o(` 展示服务器 `,-1),h(`code`,null,`storage/logs`,-1),o(` 下 Laravel 应用日志文件尾部(按行)。仅超级管理员可访问;请勿将日志内容外传。 `,-1)]]),_:1}),_(k,{wrap:``,size:12,style:{"margin-bottom":`12px`}},{default:a(()=>[n[5]||=h(`span`,{class:`system-logs-tool-label`},`日志文件`,-1),_(f,{modelValue:D.value,"onUpdate:modelValue":n[0]||=e=>D.value=e,"allow-clear":``,placeholder:`选择文件`,style:{width:`260px`},loading:x.value},{default:a(()=>[(t(!0),p(l,null,y(O.value,e=>(t(),s(u,{key:e.name,value:e.name},{default:a(()=>[o(d(e.name)+``+d(P(e.size_bytes))+``+d(g(S)(e.modified_at))+` `,1)]),_:2},1032,[`value`]))),128))]),_:1},8,[`modelValue`,`loading`]),n[6]||=h(`span`,{class:`system-logs-tool-label`},`尾部行数`,-1),_(m,{modelValue:E.value,"onUpdate:modelValue":n[1]||=e=>E.value=e,min:50,max:5e3,step:50,style:{width:`120px`}},null,8,[`modelValue`]),_(v,{modelValue:T.value,"onUpdate:modelValue":n[2]||=e=>T.value=e,placeholder:`在行内筛选关键字`,"allow-clear":``,style:{width:`220px`}},null,8,[`modelValue`]),_(b,{type:`primary`,loading:x.value,onClick:I},{default:a(()=>[...n[4]||=[o(`刷新`,-1)]]),_:1},8,[`loading`])]),_:1}),A.value?(t(),s(r,{key:0,type:`error`,style:{"margin-bottom":`8px`}},{default:a(()=>[o(d(A.value),1)]),_:1})):c(``,!0),h(`div`,{ref_key:`scrollEl`,ref:j,class:`system-logs-panel`,tabindex:`0`,role:`region`,"aria-label":`日志内容`},[_(M,{loading:x.value,style:{display:`block`,"min-height":`120px`}},{default:a(()=>[N.value.length?(t(),p(`pre`,C,d(N.value.join(`
import{n as e}from"./axios-CiYFffbI.js";import{I as t,N as n,O as r,V as i,Y as a,_ as o,d as s,f as c,i as l,it as u,kt as d,l as f,p,q as m,u as h,ut as g,v as _,y as v,z as y}from"./runtime-core.esm-bundler-CnFWH3R5.js";import{n as b}from"./http-LCi9aT1G.js";import{u as x}from"./index-DHqNSBjF.js";import{t as S}from"./datetime-DLy52ZIc.js";var C={key:0,class:`system-logs-pre`},w={key:1,class:`system-logs-empty`},T=x(v({__name:`SystemLogs`,setup(v){let x=u(!1),T=u(``),E=u(400),D=u(``),O=u([]),k=u([]),A=u(null),j=u(null),M=u(!1),N=f(()=>{let e=T.value.trim().toLowerCase();return e?k.value.filter(t=>t.toLowerCase().includes(e)):k.value});function P(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(2)} MB`}async function F(){await r();let e=j.value;e&&(e.scrollTop=e.scrollHeight)}async function I(){x.value=!0,A.value=null;try{let{data:e}=await b.get(`/system-logs`,{params:{file:D.value||void 0,lines:E.value}});O.value=e.files??[],M.value=!0,D.value=e.file??``,await r(),M.value=!1,k.value=e.lines??[],A.value=e.error??null,await F()}catch(t){e.error(t?.response?.data?.message??`加载系统日志失败`),k.value=[],M.value=!1}finally{x.value=!1}}return m(D,()=>{M.value||I()}),n(I),(e,n)=>{let r=i(`a-alert`),u=i(`a-option`),f=i(`a-select`),m=i(`a-input-number`),v=i(`a-input`),b=i(`a-button`),k=i(`a-space`),M=i(`a-spin`),F=i(`a-card`);return t(),s(F,{title:`系统设置 / 系统日志`},{default:a(()=>[_(r,{type:`warning`,style:{"margin-bottom":`12px`}},{default:a(()=>[...n[3]||=[o(` 展示服务器 `,-1),h(`code`,null,`storage/logs`,-1),o(` 下 Laravel 应用日志文件尾部(按行)。仅超级管理员可访问;请勿将日志内容外传。 `,-1)]]),_:1}),_(k,{wrap:``,size:12,style:{"margin-bottom":`12px`}},{default:a(()=>[n[5]||=h(`span`,{class:`system-logs-tool-label`},`日志文件`,-1),_(f,{modelValue:D.value,"onUpdate:modelValue":n[0]||=e=>D.value=e,"allow-clear":``,placeholder:`选择文件`,style:{width:`260px`},loading:x.value},{default:a(()=>[(t(!0),p(l,null,y(O.value,e=>(t(),s(u,{key:e.name,value:e.name},{default:a(()=>[o(d(e.name)+``+d(P(e.size_bytes))+``+d(g(S)(e.modified_at))+` `,1)]),_:2},1032,[`value`]))),128))]),_:1},8,[`modelValue`,`loading`]),n[6]||=h(`span`,{class:`system-logs-tool-label`},`尾部行数`,-1),_(m,{modelValue:E.value,"onUpdate:modelValue":n[1]||=e=>E.value=e,min:50,max:5e3,step:50,style:{width:`120px`}},null,8,[`modelValue`]),_(v,{modelValue:T.value,"onUpdate:modelValue":n[2]||=e=>T.value=e,placeholder:`在行内筛选关键字`,"allow-clear":``,style:{width:`220px`}},null,8,[`modelValue`]),_(b,{type:`primary`,loading:x.value,onClick:I},{default:a(()=>[...n[4]||=[o(`刷新`,-1)]]),_:1},8,[`loading`])]),_:1}),A.value?(t(),s(r,{key:0,type:`error`,style:{"margin-bottom":`8px`}},{default:a(()=>[o(d(A.value),1)]),_:1})):c(``,!0),h(`div`,{ref_key:`scrollEl`,ref:j,class:`system-logs-panel`,tabindex:`0`,role:`region`,"aria-label":`日志内容`},[_(M,{loading:x.value,style:{display:`block`,"min-height":`120px`}},{default:a(()=>[N.value.length?(t(),p(`pre`,C,d(N.value.join(`
`)),1)):x.value?c(``,!0):(t(),p(`div`,w,`暂无日志内容或无权限读取文件`))]),_:1},8,[`loading`])],512)]),_:1})}}}),[[`__scopeId`,`data-v-00758b3f`]]);export{T as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +0,0 @@
.tg-verify-cred-add[data-v-1297b135]{margin-bottom:12px}.tg-verify-cred-add__hint[data-v-1297b135]{color:var(--color-text-3);font-size:12px;line-height:1.5}.tg-venue-block[data-v-1297b135]{width:100%}.tg-venue-block__add[data-v-1297b135]{margin-bottom:10px}.tg-venue-table-scroll[data-v-1297b135]{box-sizing:border-box;width:100%;max-width:100%;overflow-x:auto}.tg-venue-table[data-v-1297b135]{width:100%;min-width:0}.tg-venue-quota-input[data-v-1297b135] .arco-input-wrapper{min-width:120px}.tg-venue-actions[data-v-1297b135]{box-sizing:border-box;flex-wrap:nowrap;justify-content:center;align-items:center;gap:0;width:100%;display:inline-flex}.tg-venue-actions[data-v-1297b135] .arco-btn-size-small{padding-left:4px;padding-right:4px}.tg-list-actions[data-v-1297b135]{flex-wrap:wrap;justify-content:flex-start;row-gap:2px;max-width:100%}.activity-cover-carousel-wrap[data-v-1297b135]{flex-wrap:wrap;align-items:flex-start;gap:20px;width:100%;display:flex}.activity-cover-carousel-row__col[data-v-1297b135]{flex:320px;min-width:min(100%,320px)}.activity-cover-carousel-row__sub[data-v-1297b135]{color:var(--color-text-1);margin-bottom:8px;font-weight:500}.activity-cover-thumb[data-v-1297b135]{object-fit:cover;cursor:zoom-in;border:1px solid #e5e6eb;border-radius:4px;width:120px;height:70px}.activity-gallery-grid[data-v-1297b135]{flex-wrap:wrap;align-items:flex-start;gap:12px;width:100%;display:flex}.activity-gallery-item[data-v-1297b135]{flex-direction:column;align-items:flex-start;gap:8px;display:flex}.activity-gallery-thumb[data-v-1297b135]{object-fit:cover;cursor:zoom-in;border:1px solid #e5e6eb;border-radius:4px;width:120px;height:80px}.activity-gallery-thumb--video[data-v-1297b135]{cursor:default}.activity-address-coord-row[data-v-1297b135]{flex-wrap:wrap;align-items:center;gap:12px;width:100%;display:flex}.activity-address-coord-row__address[data-v-1297b135]{flex:45%;min-width:220px;max-width:100%}.activity-address-coord-row__lng[data-v-1297b135],.activity-address-coord-row__lat[data-v-1297b135]{flex:180px;width:200px;min-width:160px}.activity-address-coord-row__map[data-v-1297b135]{flex-shrink:0}

@ -0,0 +1 @@
.tg-venue-block[data-v-9e33a7fc]{width:100%}.tg-venue-block__add[data-v-9e33a7fc]{margin-bottom:10px}.tg-venue-table-scroll[data-v-9e33a7fc]{box-sizing:border-box;width:100%;max-width:100%;overflow-x:auto}.tg-venue-table[data-v-9e33a7fc]{width:100%;min-width:0}.tg-venue-quota-input[data-v-9e33a7fc] .arco-input-wrapper{min-width:120px}.tg-venue-actions[data-v-9e33a7fc]{box-sizing:border-box;flex-wrap:nowrap;justify-content:center;align-items:center;gap:0;width:100%;display:inline-flex}.tg-venue-actions[data-v-9e33a7fc] .arco-btn-size-small{padding-left:4px;padding-right:4px}.tg-list-actions[data-v-9e33a7fc]{flex-wrap:wrap;justify-content:flex-start;row-gap:2px;max-width:100%}.activity-cover-carousel-wrap[data-v-9e33a7fc]{flex-wrap:wrap;align-items:flex-start;gap:20px;width:100%;display:flex}.activity-cover-carousel-row__col[data-v-9e33a7fc]{flex:320px;min-width:min(100%,320px)}.activity-cover-carousel-row__sub[data-v-9e33a7fc]{color:var(--color-text-1);margin-bottom:8px;font-weight:500}.activity-cover-thumb[data-v-9e33a7fc]{object-fit:cover;cursor:zoom-in;border:1px solid #e5e6eb;border-radius:4px;width:120px;height:70px}.activity-gallery-grid[data-v-9e33a7fc]{flex-wrap:wrap;align-items:flex-start;gap:12px;width:100%;display:flex}.activity-gallery-item[data-v-9e33a7fc]{flex-direction:column;align-items:flex-start;gap:8px;display:flex}.activity-gallery-thumb[data-v-9e33a7fc]{object-fit:cover;cursor:zoom-in;border:1px solid #e5e6eb;border-radius:4px;width:120px;height:80px}.activity-gallery-thumb--video[data-v-9e33a7fc]{cursor:default}.activity-address-coord-row[data-v-9e33a7fc]{flex-wrap:wrap;align-items:center;gap:12px;width:100%;display:flex}.activity-address-coord-row__address[data-v-9e33a7fc]{flex:45%;min-width:220px;max-width:100%}.activity-address-coord-row__lng[data-v-9e33a7fc],.activity-address-coord-row__lat[data-v-9e33a7fc]{flex:180px;width:200px;min-width:160px}.activity-address-coord-row__map[data-v-9e33a7fc]{flex-shrink:0}.tg-detail-hub-pane[data-v-9e33a7fc]{box-sizing:border-box;max-height:min(70vh,680px);padding-right:2px;overflow-y:auto}.tg-hub-activity__title-row[data-v-9e33a7fc]{flex-wrap:wrap;justify-content:space-between;align-items:flex-start;gap:12px 16px;display:flex}.tg-hub-activity__name[data-v-9e33a7fc]{flex:200px;margin:0!important}.tg-hub-activity__tags[data-v-9e33a7fc]{flex-wrap:wrap;gap:8px;margin-top:10px;display:flex}.tg-hub-divider[data-v-9e33a7fc]{margin:14px 0!important}.tg-hub-section[data-v-9e33a7fc]{margin-bottom:20px}.tg-hub-section[data-v-9e33a7fc]:last-child{margin-bottom:2px}.tg-hub-section__title[data-v-9e33a7fc]{color:var(--color-text-2);letter-spacing:.02em;margin:0 0 10px;font-size:13px;font-weight:600}.tg-hub-desc[data-v-9e33a7fc]{width:100%}.tg-hub-desc[data-v-9e33a7fc] .arco-descriptions-item-label{white-space:nowrap;width:112px}.tg-hub-media[data-v-9e33a7fc]{flex-wrap:wrap;align-items:flex-start;gap:20px;display:flex}.tg-hub-media__sub[data-v-9e33a7fc]{color:var(--color-text-3);margin-bottom:8px;font-size:12px}.tg-hub-media__cover-img[data-v-9e33a7fc]{object-fit:cover;border:1px solid var(--color-border-2);cursor:zoom-in;border-radius:6px;width:200px;max-width:100%;height:112px;display:block}.tg-hub-media__gallery[data-v-9e33a7fc]{flex:280px;min-width:0}.tg-hub-gallery-scroll[data-v-9e33a7fc]{flex-wrap:nowrap;gap:10px;max-width:100%;padding-bottom:6px;display:flex;overflow-x:auto}.tg-hub-gallery-thumb-wrap[data-v-9e33a7fc]{flex:none}.tg-hub-gallery-thumb[data-v-9e33a7fc]{object-fit:cover;border:1px solid var(--color-border-2);cursor:zoom-in;border-radius:6px;width:128px;height:80px;display:block}.tg-hub-gallery-thumb--video[data-v-9e33a7fc]{cursor:default}.tg-hub-table-wrap[data-v-9e33a7fc]{border:1px solid var(--color-border-2);border-radius:6px;overflow:hidden}.tg-hub-rich-box[data-v-9e33a7fc]{border:1px solid var(--color-border-2);background:var(--color-fill-1);border-radius:6px;max-height:280px;padding:12px 14px;overflow:auto}.tg-hub-rich[data-v-9e33a7fc]{color:var(--color-text-1);font-size:14px;line-height:1.65}.tg-hub-rich[data-v-9e33a7fc] img{max-width:100%;height:auto}.tg-hub-rich[data-v-9e33a7fc] p{margin:.5em 0}.tg-hub-rich[data-v-9e33a7fc] p:first-child{margin-top:0}.tg-hub-rich[data-v-9e33a7fc] p:last-child{margin-bottom:0}

@ -1 +0,0 @@
import{n as e}from"./axios-CiYFffbI.js";import{I as t,N as n,V as r,Y as i,_ as a,d as o,i as s,it as c,kt as l,nt as u,p as d,u as f,ut as p,v as m,y as h,z as g}from"./runtime-core.esm-bundler-CnFWH3R5.js";import{n as _}from"./http-LCi9aT1G.js";import{t as v}from"./listTableRowIndex-Bl-nc9Qt.js";import{n as y,t as b}from"./datetime-DLy52ZIc.js";import{t as x}from"./bookingType-sDQIPutU.js";import{t as S}from"./reservationStatus-DPnogIlu.js";var C={style:{"font-family":`monospace`,"font-size":`12px`}},w=1680,T=h({__name:`TicketGrabRegistrations`,setup(h){let T=c(!1),E=c(`all`),D=c(``),O=c(void 0),k=c([]),A=u({current:1,pageSize:10,total:0}),j=c([]),M=c([]);async function N(){try{let{data:e}=await _.get(`/ticket-grab-events/options`,{params:{limit:2e3}});M.value=e.data??[]}catch{M.value=[]}}async function P(){T.value=!0;try{let{data:e}=await _.get(`/activity-registrations`,{params:{reservation_kind:`ticket_grab`,ticket_grab_event_id:O.value||void 0,status:E.value,keyword:D.value||void 0,start_date:k.value?.[0]||void 0,end_date:k.value?.[1]||void 0,page:A.current,page_size:A.pageSize}});j.value=e.data,A.total=e.total}catch(t){e.error(t?.response?.data?.message??`加载失败`)}finally{T.value=!1}}function F(e){A.current=e,P()}function I(e){A.pageSize=e,A.current=1,P()}return n(async()=>{await N(),await P()}),(e,n)=>{let c=r(`a-option`),u=r(`a-select`),h=r(`a-radio`),_=r(`a-radio-group`),N=r(`a-input`),L=r(`a-range-picker`),R=r(`a-button`),z=r(`a-space`),B=r(`a-table-column`),V=r(`a-tag`),H=r(`a-table`),U=r(`a-card`);return t(),o(U,{title:`抢票管理 / 抢票报名`,bordered:!1},{default:i(()=>[m(z,{direction:`vertical`,fill:``},{default:i(()=>[m(z,{wrap:``,size:12},{default:i(()=>[m(u,{modelValue:O.value,"onUpdate:modelValue":n[0]||=e=>O.value=e,"allow-clear":``,placeholder:`抢票活动(全部)`,style:{width:`260px`},"allow-search":``,onChange:n[1]||=()=>{A.current=1,P()}},{default:i(()=>[(t(!0),d(s,null,g(M.value,e=>(t(),o(c,{key:e.id,value:e.id},{default:i(()=>[a(l(e.title),1)]),_:2},1032,[`value`]))),128))]),_:1},8,[`modelValue`]),m(_,{modelValue:E.value,"onUpdate:modelValue":n[2]||=e=>E.value=e,type:`button`,size:`small`,onChange:P},{default:i(()=>[m(h,{value:`all`},{default:i(()=>[...n[6]||=[a(`全部`,-1)]]),_:1}),m(h,{value:`pending`},{default:i(()=>[...n[7]||=[a(`待核销`,-1)]]),_:1}),m(h,{value:`verified`},{default:i(()=>[...n[8]||=[a(`已核销`,-1)]]),_:1}),m(h,{value:`cancelled`},{default:i(()=>[...n[9]||=[a(`已取消`,-1)]]),_:1}),m(h,{value:`expired`},{default:i(()=>[...n[10]||=[a(`已过期`,-1)]]),_:1})]),_:1},8,[`modelValue`]),m(N,{modelValue:D.value,"onUpdate:modelValue":n[3]||=e=>D.value=e,placeholder:`姓名 / 身份证 / token`,"allow-clear":``,style:{width:`220px`}},null,8,[`modelValue`]),m(L,{modelValue:k.value,"onUpdate:modelValue":n[4]||=e=>k.value=e,style:{width:`260px`}},null,8,[`modelValue`]),m(R,{type:`primary`,onClick:n[5]||=()=>{A.current=1,P()}},{default:i(()=>[...n[11]||=[a(` 查询 `,-1)]]),_:1})]),_:1}),m(H,{scroll:{x:w},data:j.value,loading:T.value,"row-key":`id`,pagination:{current:A.current,pageSize:A.pageSize,total:A.total,showTotal:!0,onChange:F,onPageSizeChange:I}},{columns:i(()=>[m(B,{title:``,width:50,ellipsis:!0,tooltip:!0},{cell:i(({rowIndex:e})=>[a(l(p(v)(e,A.current,A.pageSize)),1)]),_:1}),m(B,{title:`抢票活动`,width:200,ellipsis:!0,tooltip:!0},{cell:i(({record:e})=>[a(l(e.ticket_grab_event?.title??`-`),1)]),_:1}),m(B,{title:`场馆`,width:160,ellipsis:!0,tooltip:!0},{cell:i(({record:e})=>[a(l(e.venue?.name??`-`),1)]),_:1}),m(B,{title:`姓名`,"data-index":`visitor_name`,width:100}),m(B,{title:`身份证`,"data-index":`id_card`,width:180,ellipsis:!0,tooltip:!0}),m(B,{title:`入馆日`,width:120},{cell:i(({record:e})=>[a(l(e.entry_date?p(y)(String(e.entry_date)):`-`),1)]),_:1}),m(B,{title:`预约类型`,width:100},{cell:i(({record:e})=>[a(l(p(x)(e.booking_type,e.ticket_count)),1)]),_:1}),m(B,{title:`票数`,width:80},{cell:i(({record:e})=>[a(l(e.ticket_count??1),1)]),_:1}),m(B,{title:`状态`,width:100},{cell:i(({record:e})=>[m(V,{color:e.status===`verified`?`green`:e.status===`pending`?`arcoblue`:`gray`},{default:i(()=>[a(l(p(S)(e.status)),1)]),_:2},1032,[`color`])]),_:1}),m(B,{title:`下单时间`,width:170},{cell:i(({record:e})=>[a(l(p(b)(e.created_at)),1)]),_:1}),m(B,{title:`核销时间`,width:170},{cell:i(({record:e})=>[a(l(e.verified_at?p(b)(String(e.verified_at)):`-`),1)]),_:1}),m(B,{title:`核销 Token`,width:220,ellipsis:!0,tooltip:!0},{cell:i(({record:e})=>[f(`span`,C,l(e.qr_token),1)]),_:1})]),_:1},8,[`scroll`,`data`,`loading`,`pagination`])]),_:1})]),_:1})}}});export{T as default};

File diff suppressed because one or more lines are too long

@ -1 +1 @@
import{n as e}from"./axios-CiYFffbI.js";import{I as t,N as n,V as r,Y as i,_ as a,d as o,it as s,kt as c,nt as l,u,ut as d,v as f,y as p}from"./runtime-core.esm-bundler-CnFWH3R5.js";import{n as m}from"./http-LCi9aT1G.js";import{u as h}from"./index-B-4Rg8Jl.js";import{t as g}from"./listTableRowIndex-Bl-nc9Qt.js";import{n as _,t as v}from"./datetime-DLy52ZIc.js";import{t as y}from"./bookingType-sDQIPutU.js";import{t as b}from"./reservationStatus-DPnogIlu.js";var x={class:`verify-list-toolbar`},S=1780,C=h(p({__name:`TicketGrabVerify`,setup(p){let h=s(!1),C=s([]),w=s(``),T=s(!1),E=s(`all`),D=s(``),O=s([]),k=l({current:1,pageSize:10});async function A(){h.value=!0;try{let e={status:E.value,keyword:D.value||void 0,reservation_kind:`ticket_grab`};O.value?.length===2&&(e.start_date=O.value[0],e.end_date=O.value[1],e.date_field=`entry_date`);let{data:t}=await m.get(`/reservations`,{params:e});C.value=t,k.current=1}catch(t){e.error(t?.response?.data?.message??`加载预约列表失败`)}finally{h.value=!1}}function j(){A()}function M(){E.value=`all`,D.value=``,O.value=[],A()}async function N(){if(!w.value){e.warning(`请输入二维码 token`);return}T.value=!0;try{await m.post(`/reservations/verify`,{qr_token:w.value}),e.success(`核销成功`),w.value=``,await A()}catch(t){e.error(t?.response?.data?.message??`核销失败`)}finally{T.value=!1}}return n(A),(e,n)=>{let s=r(`a-alert`),l=r(`a-input`),p=r(`a-button`),m=r(`a-space`),P=r(`a-radio`),F=r(`a-radio-group`),I=r(`a-range-picker`),L=r(`a-table-column`),R=r(`a-tag`),z=r(`a-table`),B=r(`a-card`);return t(),o(B,{title:`抢票管理 / 抢票核销`,bordered:!1},{default:i(()=>[f(m,{direction:`vertical`,fill:``},{default:i(()=>[f(s,null,{default:i(()=>[...n[5]||=[a(`抢票预约按「入馆日」为当天方可核销。输入二维码 token 核销。`,-1)]]),_:1}),f(m,{wrap:``,size:12},{default:i(()=>[f(l,{modelValue:w.value,"onUpdate:modelValue":n[0]||=e=>w.value=e,style:{width:`min(100%, 420px)`},placeholder:`请输入二维码 token`,"allow-clear":``},null,8,[`modelValue`]),f(p,{type:`primary`,loading:T.value,onClick:N},{default:i(()=>[...n[6]||=[a(`立即核销`,-1)]]),_:1},8,[`loading`])]),_:1}),u(`div`,x,[f(m,{wrap:``,size:12},{default:i(()=>[f(F,{modelValue:E.value,"onUpdate:modelValue":n[1]||=e=>E.value=e,type:`button`,size:`small`,onChange:A},{default:i(()=>[f(P,{value:`all`},{default:i(()=>[...n[7]||=[a(`全部`,-1)]]),_:1}),f(P,{value:`pending`},{default:i(()=>[...n[8]||=[a(`待核销`,-1)]]),_:1}),f(P,{value:`verified`},{default:i(()=>[...n[9]||=[a(`已核销`,-1)]]),_:1}),f(P,{value:`cancelled`},{default:i(()=>[...n[10]||=[a(`已取消`,-1)]]),_:1}),f(P,{value:`expired`},{default:i(()=>[...n[11]||=[a(`已过期`,-1)]]),_:1})]),_:1},8,[`modelValue`]),f(l,{modelValue:D.value,"onUpdate:modelValue":n[2]||=e=>D.value=e,placeholder:`姓名 / 手机 / 身份证 / token`,"allow-clear":``,style:{width:`240px`}},null,8,[`modelValue`]),f(I,{modelValue:O.value,"onUpdate:modelValue":n[3]||=e=>O.value=e,style:{width:`260px`}},null,8,[`modelValue`]),f(p,{type:`primary`,onClick:j},{default:i(()=>[...n[12]||=[a(`查询`,-1)]]),_:1}),f(p,{onClick:M},{default:i(()=>[...n[13]||=[a(`重置`,-1)]]),_:1}),f(p,{onClick:A},{default:i(()=>[...n[14]||=[a(`刷新列表`,-1)]]),_:1})]),_:1})]),f(z,{class:`list-data-table verify-table`,scroll:{x:S},data:C.value,loading:h.value,"row-key":`id`,pagination:{current:k.current,pageSize:k.pageSize,total:C.value.length,showTotal:!0},onPageChange:n[4]||=e=>k.current=e},{columns:i(()=>[f(L,{title:``,width:50,ellipsis:!0,tooltip:!0},{cell:i(({rowIndex:e})=>[a(c(d(g)(e,k.current,k.pageSize)),1)]),_:1}),f(L,{title:`预约场次`,width:220,ellipsis:!0,tooltip:!0},{cell:i(({record:e})=>[a(c(e.ticket_grab_event?.title??`-`),1)]),_:1}),f(L,{title:`场馆`,width:180,ellipsis:!0,tooltip:!0},{cell:i(({record:e})=>[a(c(e.venue?.name??`-`),1)]),_:1}),f(L,{title:`姓名`,"data-index":`visitor_name`,width:100}),f(L,{title:`身份证`,"data-index":`id_card`,width:180,ellipsis:!0,tooltip:!0}),f(L,{title:`手机号`,"data-index":`visitor_phone`,width:120}),f(L,{title:`预约类型`,width:100},{cell:i(({record:e})=>[a(c(d(y)(e.booking_type,e.ticket_count)),1)]),_:1}),f(L,{title:`场次时间`,width:140},{cell:i(({record:e})=>[a(c(e.entry_date?d(_)(String(e.entry_date)):`-`),1)]),_:1}),f(L,{title:`状态`,width:100},{cell:i(({record:e})=>[f(R,{color:e.status===`verified`?`green`:e.status===`pending`?`arcoblue`:e.status===`expired`?`orange`:`gray`},{default:i(()=>[a(c(d(b)(e.status)),1)]),_:2},1032,[`color`])]),_:1}),f(L,{title:`预约时间`,width:175},{cell:i(({record:e})=>[a(c(d(v)(e.created_at)),1)]),_:1}),f(L,{title:`核销时间`,width:175},{cell:i(({record:e})=>[a(c(d(v)(e.verified_at)),1)]),_:1}),f(L,{title:`二维码 token`,"data-index":`qr_token`,width:200,ellipsis:!0,tooltip:!0,fixed:`right`})]),_:1},8,[`scroll`,`data`,`loading`,`pagination`])]),_:1})]),_:1})}}}),[[`__scopeId`,`data-v-f1a484a3`]]);export{C as default};
import{n as e}from"./axios-CiYFffbI.js";import{I as t,N as n,V as r,Y as i,_ as a,d as o,it as s,kt as c,nt as l,u,ut as d,v as f,y as p}from"./runtime-core.esm-bundler-CnFWH3R5.js";import{n as m}from"./http-LCi9aT1G.js";import{u as h}from"./index-DHqNSBjF.js";import{t as g}from"./listTableRowIndex-Bl-nc9Qt.js";import{n as _,t as v}from"./datetime-DLy52ZIc.js";import{t as y}from"./bookingType-sDQIPutU.js";import{t as b}from"./reservationStatus-DPnogIlu.js";var x={class:`verify-list-toolbar`},S=1780,C=h(p({__name:`TicketGrabVerify`,setup(p){let h=s(!1),C=s([]),w=s(``),T=s(!1),E=s(`all`),D=s(``),O=s([]),k=l({current:1,pageSize:10});async function A(){h.value=!0;try{let e={status:E.value,keyword:D.value||void 0,reservation_kind:`ticket_grab`};O.value?.length===2&&(e.start_date=O.value[0],e.end_date=O.value[1],e.date_field=`entry_date`);let{data:t}=await m.get(`/reservations`,{params:e});C.value=t,k.current=1}catch(t){e.error(t?.response?.data?.message??`加载预约列表失败`)}finally{h.value=!1}}function j(){A()}function M(){E.value=`all`,D.value=``,O.value=[],A()}async function N(){if(!w.value){e.warning(`请输入二维码 token`);return}T.value=!0;try{await m.post(`/reservations/verify`,{qr_token:w.value}),e.success(`核销成功`),w.value=``,await A()}catch(t){e.error(t?.response?.data?.message??`核销失败`)}finally{T.value=!1}}return n(A),(e,n)=>{let s=r(`a-alert`),l=r(`a-input`),p=r(`a-button`),m=r(`a-space`),P=r(`a-radio`),F=r(`a-radio-group`),I=r(`a-range-picker`),L=r(`a-table-column`),R=r(`a-tag`),z=r(`a-table`),B=r(`a-card`);return t(),o(B,{title:`抢票管理 / 抢票核销`,bordered:!1},{default:i(()=>[f(m,{direction:`vertical`,fill:``},{default:i(()=>[f(s,null,{default:i(()=>[...n[5]||=[a(`抢票预约按「入馆日」为当天方可核销。输入二维码 token 核销。`,-1)]]),_:1}),f(m,{wrap:``,size:12},{default:i(()=>[f(l,{modelValue:w.value,"onUpdate:modelValue":n[0]||=e=>w.value=e,style:{width:`min(100%, 420px)`},placeholder:`请输入二维码 token`,"allow-clear":``},null,8,[`modelValue`]),f(p,{type:`primary`,loading:T.value,onClick:N},{default:i(()=>[...n[6]||=[a(`立即核销`,-1)]]),_:1},8,[`loading`])]),_:1}),u(`div`,x,[f(m,{wrap:``,size:12},{default:i(()=>[f(F,{modelValue:E.value,"onUpdate:modelValue":n[1]||=e=>E.value=e,type:`button`,size:`small`,onChange:A},{default:i(()=>[f(P,{value:`all`},{default:i(()=>[...n[7]||=[a(`全部`,-1)]]),_:1}),f(P,{value:`pending`},{default:i(()=>[...n[8]||=[a(`待核销`,-1)]]),_:1}),f(P,{value:`verified`},{default:i(()=>[...n[9]||=[a(`已核销`,-1)]]),_:1}),f(P,{value:`cancelled`},{default:i(()=>[...n[10]||=[a(`已取消`,-1)]]),_:1}),f(P,{value:`expired`},{default:i(()=>[...n[11]||=[a(`已过期`,-1)]]),_:1})]),_:1},8,[`modelValue`]),f(l,{modelValue:D.value,"onUpdate:modelValue":n[2]||=e=>D.value=e,placeholder:`姓名 / 手机 / 身份证 / token`,"allow-clear":``,style:{width:`240px`}},null,8,[`modelValue`]),f(I,{modelValue:O.value,"onUpdate:modelValue":n[3]||=e=>O.value=e,style:{width:`260px`}},null,8,[`modelValue`]),f(p,{type:`primary`,onClick:j},{default:i(()=>[...n[12]||=[a(`查询`,-1)]]),_:1}),f(p,{onClick:M},{default:i(()=>[...n[13]||=[a(`重置`,-1)]]),_:1}),f(p,{onClick:A},{default:i(()=>[...n[14]||=[a(`刷新列表`,-1)]]),_:1})]),_:1})]),f(z,{class:`list-data-table verify-table`,scroll:{x:S},data:C.value,loading:h.value,"row-key":`id`,pagination:{current:k.current,pageSize:k.pageSize,total:C.value.length,showTotal:!0},onPageChange:n[4]||=e=>k.current=e},{columns:i(()=>[f(L,{title:``,width:50,ellipsis:!0,tooltip:!0},{cell:i(({rowIndex:e})=>[a(c(d(g)(e,k.current,k.pageSize)),1)]),_:1}),f(L,{title:`预约场次`,width:220,ellipsis:!0,tooltip:!0},{cell:i(({record:e})=>[a(c(e.ticket_grab_event?.title??`-`),1)]),_:1}),f(L,{title:`场馆`,width:180,ellipsis:!0,tooltip:!0},{cell:i(({record:e})=>[a(c(e.venue?.name??`-`),1)]),_:1}),f(L,{title:`姓名`,"data-index":`visitor_name`,width:100}),f(L,{title:`身份证`,"data-index":`id_card`,width:180,ellipsis:!0,tooltip:!0}),f(L,{title:`手机号`,"data-index":`visitor_phone`,width:120}),f(L,{title:`预约类型`,width:100},{cell:i(({record:e})=>[a(c(d(y)(e.booking_type,e.ticket_count)),1)]),_:1}),f(L,{title:`场次时间`,width:140},{cell:i(({record:e})=>[a(c(e.entry_date?d(_)(String(e.entry_date)):`-`),1)]),_:1}),f(L,{title:`状态`,width:100},{cell:i(({record:e})=>[f(R,{color:e.status===`verified`?`green`:e.status===`pending`?`arcoblue`:e.status===`expired`?`orange`:`gray`},{default:i(()=>[a(c(d(b)(e.status)),1)]),_:2},1032,[`color`])]),_:1}),f(L,{title:`预约时间`,width:175},{cell:i(({record:e})=>[a(c(d(v)(e.created_at)),1)]),_:1}),f(L,{title:`核销时间`,width:175},{cell:i(({record:e})=>[a(c(d(v)(e.verified_at)),1)]),_:1}),f(L,{title:`二维码 token`,"data-index":`qr_token`,width:200,ellipsis:!0,tooltip:!0,fixed:`right`})]),_:1},8,[`scroll`,`data`,`loading`,`pagination`])]),_:1})]),_:1})}}}),[[`__scopeId`,`data-v-f1a484a3`]]);export{C as default};

File diff suppressed because one or more lines are too long

@ -1 +0,0 @@
import{n as e}from"./axios-CiYFffbI.js";import{I as t,N as n,V as r,Y as i,_ as a,i as o,it as s,kt as c,nt as l,p as u,u as d,v as f,y as p}from"./runtime-core.esm-bundler-CnFWH3R5.js";import{c as m,s as h,u as g}from"./index-B-4Rg8Jl.js";import{i as _,n as v,o as y,r as b,t as x}from"./h5Http-CIzJQiXt.js";var S={class:`m-verify-page`},C={class:`m-verify-hero`},w={class:`m-verify-sub`},T={class:`m-verify-card`},E={key:0,class:`m-verify-tip`},D={key:1,class:`m-verify-tip`},O=g(p({__name:`VerifyLogin`,setup(p){let g=m(),O=h(),k=s(!1),A=s(``),j=s(``),M=s(``),N=s(!1),P=l({username:``,password:``});function F(e){let t=O.query[e];return(typeof t==`string`?t:Array.isArray(t)?String(t[0]??``):``).trim()}async function I(){let e=A.value,t=j.value;if(e.length>=6){N.value=!0;try{let{data:t}=await y.get(`/verify-portal/preview`,{params:{portal_code:e}});M.value=String(t?.event_title||``).trim()||``}catch{M.value=``}finally{N.value=!1}return}if(t.length>=32){N.value=!0;try{let{data:e}=await y.get(`/verify-portal/preview`,{params:{portal_token:t}});M.value=String(e?.event_title||``).trim()||``}catch{M.value=``}finally{N.value=!1}return}M.value=``}n(()=>{let e=F(`v`).toLowerCase(),t=F(`portal`);e.length>=6?(A.value=e,j.value=``,localStorage.setItem(b,e),localStorage.removeItem(_)):t.length>=32?(j.value=t,A.value=``,localStorage.setItem(_,t),localStorage.removeItem(b)):(A.value=localStorage.getItem(`szkp_verify_portal_code`)||``,j.value=localStorage.getItem(`szkp_verify_portal_legacy_token`)||``),I()});function L(){return O.path.startsWith(`/m/`)?`/m/verify`:`/h5/verify/scan`}async function R(){k.value=!0;try{if(A.value.length>=6){let{data:t}=await y.post(`/verify-portal/login`,{portal_code:A.value,username:P.username.trim(),password:P.password});localStorage.setItem(x,t.token),localStorage.setItem(`${x}_saved_at`,String(Date.now())),localStorage.setItem(v,`portal`),e.success(`登录成功`),g.replace(L());return}if(j.value.length>=32){let{data:t}=await y.post(`/verify-portal/login`,{portal_token:j.value,username:P.username.trim(),password:P.password});localStorage.setItem(x,t.token),localStorage.setItem(`${x}_saved_at`,String(Date.now())),localStorage.setItem(v,`portal`),e.success(`登录成功`),g.replace(L());return}let{data:t}=await y.post(`/auth/login`,{...P,client:`h5_verify`});localStorage.setItem(x,t.token),localStorage.setItem(`${x}_saved_at`,String(Date.now())),localStorage.setItem(v,`admin`),localStorage.removeItem(b),localStorage.removeItem(_),e.success(`登录成功`),g.replace(L())}catch(t){e.error(t?.response?.data?.message??`登录失败`)}finally{k.value=!1}}return(e,n)=>{let s=r(`a-input`),l=r(`a-form-item`),p=r(`a-input-password`),m=r(`a-button`),h=r(`a-form`);return t(),u(`div`,S,[d(`div`,C,[n[2]||=d(`div`,{class:`m-verify-title`},`核销入口`,-1),d(`div`,w,[A.value.length>=6||j.value.length>=32?(t(),u(o,{key:0},[a(c(N.value?`活动信息加载中…`:M.value||``),1)],64)):(t(),u(o,{key:1},[a(`超级管理员核销登录`)],64))])]),d(`div`,T,[f(h,{model:P,layout:`vertical`,onSubmitSuccess:R},{default:i(()=>[f(l,{label:`用户名`},{default:i(()=>[f(s,{modelValue:P.username,"onUpdate:modelValue":n[0]||=e=>P.username=e,placeholder:`请输入账号`,size:`large`,"allow-clear":``},null,8,[`modelValue`])]),_:1}),f(l,{label:`密码`},{default:i(()=>[f(p,{modelValue:P.password,"onUpdate:modelValue":n[1]||=e=>P.password=e,placeholder:`请输入密码`,size:`large`,"allow-clear":``},null,8,[`modelValue`])]),_:1}),f(m,{type:`primary`,long:``,size:`large`,loading:k.value,onClick:R},{default:i(()=>[...n[3]||=[a(`登录`,-1)]]),_:1},8,[`loading`])]),_:1},8,[`model`]),A.value.length>=6||j.value.length>=32?(t(),u(`p`,E,` 活动专用核销登录(活动结束后账号失效) `)):(t(),u(`p`,D,[...n[4]||=[a(``,-1),d(`strong`,null,`超级管理员`,-1),a(`可使用后台账号登录本页。场馆工作人员请打开管理员提供的带 `,-1),d(`strong`,null,`?v=短码`,-1),a(` 的专用链接。 `,-1)]])),n[5]||=d(`p`,{class:`m-verify-tip`},`登录状态将保持较长时间;若已失效会自动回到本页。`,-1)])])}}}),[[`__scopeId`,`data-v-54556c3e`]]);export{O as default};

@ -1 +0,0 @@
.m-verify-page[data-v-54556c3e]{box-sizing:border-box;background:linear-gradient(165deg,#e8f1ff 0%,#f5f7fa 45%,#fff 100%);min-height:100dvh;padding:20px 16px 32px}.m-verify-hero[data-v-54556c3e]{text-align:center;padding:28px 8px 20px}.m-verify-title[data-v-54556c3e]{color:#1d2129;letter-spacing:.02em;font-size:20px;font-weight:700}.m-verify-sub[data-v-54556c3e]{color:#86909c;margin-top:8px;font-size:14px}.m-verify-card[data-v-54556c3e]{background:#fff;border-radius:14px;max-width:420px;margin:0 auto;padding:20px;box-shadow:0 8px 28px #0f172a14}.m-verify-tip[data-v-54556c3e]{color:#86909c;margin-top:14px;font-size:12px;line-height:1.5}

@ -0,0 +1 @@
import{n as e,ot as t}from"./axios-CiYFffbI.js";import{I as n,N as r,V as i,Y as a,_ as o,it as s,p as c,u as l,v as u,y as d}from"./runtime-core.esm-bundler-CnFWH3R5.js";import{c as f,s as p,u as m}from"./index-DHqNSBjF.js";import{i as h,n as g,o as _,r as v,t as y}from"./h5Http-2MvWKf2X.js";var b={class:`m-verify-page`},x={class:`m-verify-card`},S=m(d({__name:`VerifyLogin`,setup(d){let m=f(),S=p(),C=s(!1),w=s(``);function T(){return S.path.startsWith(`/m/`)?`/m/verify`:`/h5/verify/scan`}function E(){w.value=w.value.replace(/\D/g,``).slice(0,6)}async function D(){if(E(),!/^\d{6}$/.test(w.value.trim())){e.warning(`请输入 6 位数字核销口令`);return}C.value=!0;try{let{data:t}=await _.post(`/verify-portal/login`,{password:w.value.trim()});localStorage.setItem(y,t.token),localStorage.setItem(`${y}_saved_at`,String(Date.now())),localStorage.setItem(g,`portal`),e.success(`登录成功`),m.replace(T())}catch(t){e.error(t?.response?.data?.message??`登录失败`)}finally{C.value=!1}}return r(()=>{localStorage.removeItem(v),localStorage.removeItem(h)}),(e,r)=>{let s=i(`a-input`),d=i(`a-button`);return n(),c(`div`,b,[r[4]||=l(`div`,{class:`m-verify-hero`},[l(`div`,{class:`m-verify-title`},`核销入口`)],-1),l(`div`,x,[r[2]||=l(`div`,{class:`m-verify-section-head`},`6 位数字核销口令`,-1),u(s,{modelValue:w.value,"onUpdate:modelValue":r[0]||=e=>w.value=e,maxlength:`6`,size:`large`,placeholder:`6 位数字口令`,class:`m-verify-pin`,style:{"margin-bottom":`12px`},inputmode:`numeric`,autocomplete:`one-time-code`,onInput:E,onKeyup:t(D,[`enter`])},null,8,[`modelValue`]),u(d,{type:`primary`,long:``,size:`large`,loading:C.value,onClick:D},{default:a(()=>[...r[1]||=[o(` 进入核销页 `,-1)]]),_:1},8,[`loading`]),r[3]||=l(`p`,{class:`m-verify-tip`},`登录状态将保持较长时间;失效后会自动退回本页。`,-1)])])}}}),[[`__scopeId`,`data-v-aef33543`]]);export{S as default};

@ -0,0 +1 @@
.m-verify-page[data-v-aef33543]{box-sizing:border-box;background:linear-gradient(165deg,#e8f1ff 0%,#f5f7fa 45%,#fff 100%);min-height:100dvh;padding:20px 16px 32px}.m-verify-hero[data-v-aef33543]{text-align:center;padding:28px 8px 20px}.m-verify-title[data-v-aef33543]{color:#1d2129;letter-spacing:.02em;font-size:20px;font-weight:700}.m-verify-card[data-v-aef33543]{background:#fff;border-radius:14px;max-width:420px;margin:0 auto;padding:20px;box-shadow:0 8px 28px #0f172a14}.m-verify-tip[data-v-aef33543]{color:#86909c;margin-top:14px;font-size:12px;line-height:1.5}.m-verify-section-head[data-v-aef33543]{color:#4e5969;margin-bottom:14px;font-size:15px;font-weight:600}.m-verify-pin[data-v-aef33543] input{letter-spacing:.35em;font-variant-numeric:tabular-nums;text-indent:.05em;font-size:20px}

@ -1 +1 @@
import{a as e,i as t,n,o as r,r as i,s as a,t as o}from"./dynamicAdminRoutes-Bp7nHMfT.js";export{o as flattenMenuPaths,n as getCachedAllowedPaths,i as getFirstMenuPath,t as isDynamicRoutesRegistered,e as pickDefaultPath,r as registerDynamicAdminRoutes,a as resetDynamicAdminRoutes};
import{a as e,i as t,n,o as r,r as i,s as a,t as o}from"./dynamicAdminRoutes-BAMeDyVx.js";export{o as flattenMenuPaths,n as getCachedAllowedPaths,i as getFirstMenuPath,t as isDynamicRoutesRegistered,e as pickDefaultPath,r as registerDynamicAdminRoutes,a as resetDynamicAdminRoutes};

@ -1,2 +1,2 @@
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Dashboard-BXw-W8aT.js","assets/index-B-4Rg8Jl.js","assets/axios-CiYFffbI.js","assets/runtime-core.esm-bundler-CnFWH3R5.js","assets/preload-helper-BIjWqNH5.js","assets/http-LCi9aT1G.js","assets/index-C6I69YBI.css","assets/Dashboard-D_6tkjXe.css","assets/VenueList-BIKOOMNz.js","assets/RichEditorField-CVq8dMgD.js","assets/RichEditorField-BSoIk7uU.css","assets/listTableRowIndex-Bl-nc9Qt.js","assets/mediaUrl-CPV6u7br.js","assets/VenueList-WvFrBNwX.css","assets/ActivityList-DUTVPV37.js","assets/h5Http-CIzJQiXt.js","assets/ActivityList-BeBLLFeG.css","assets/Registrations-pOUzYUXX.js","assets/bookingType-sDQIPutU.js","assets/datetime-DLy52ZIc.js","assets/reservationStatus-DPnogIlu.js","assets/Registrations-BFJ7lCw0.css","assets/Verify-Bs3lmkTP.js","assets/Verify-Dw49jI2o.css","assets/Blacklist-D37pxhFr.js","assets/Blacklist-CtQQ6LfC.css","assets/TicketGrabList-BU_pQuqX.js","assets/TicketGrabList-LRJZ5ryK.css","assets/TicketGrabRegistrations-C9INxLtz.js","assets/TicketGrabVerify-DGmDGWxl.js","assets/TicketGrabVerify-C99ifrCo.css","assets/StudyTourList-BOSu3Fqc.js","assets/StudyTourList-S9h38Ufv.css","assets/Monitor-CwQryTgE.js","assets/PagePlaceholder-Cy4-OO0C.js","assets/Leaderboard-DpnW60sP.js","assets/Alerts-CLB4PUbf.js","assets/Overview-DWCg_gXr.js","assets/Regions-wTSahatX.js","assets/Categories-C4UExwsU.js","assets/Exports-B2d1jnIW.js","assets/Admins-DC1D747T.js","assets/Roles-DV332Q28.js","assets/Menus-Di_lr0wY.js","assets/Menus-CIRuEnr6.css","assets/AuditLogs-CcyNcN17.js","assets/AuditLogs-Bd90uV6l.css","assets/Wechat-GC1DNCzj.js","assets/Map-CE8rUj1i.js","assets/Notifications-CnFkl2pO.js","assets/SystemLogs-7whmFJAk.js","assets/SystemLogs-DSVhElsT.css","assets/Dictionaries-Cq9OnVyA.js","assets/WechatUsers-CslkSm73.js"])))=>i.map(i=>d[i]);
import{n as e}from"./http-LCi9aT1G.js";import{t}from"./preload-helper-BIjWqNH5.js";var n={"/dashboard":()=>t(()=>import(`./Dashboard-BXw-W8aT.js`),__vite__mapDeps([0,1,2,3,4,5,6,7])),"/venues":()=>t(()=>import(`./VenueList-BIKOOMNz.js`),__vite__mapDeps([8,1,2,3,4,5,6,9,10,11,12,13])),"/activities":()=>t(()=>import(`./ActivityList-DUTVPV37.js`),__vite__mapDeps([14,1,2,3,4,5,6,9,10,15,11,16])),"/activities/registrations":()=>t(()=>import(`./Registrations-pOUzYUXX.js`),__vite__mapDeps([17,1,2,3,4,5,6,18,19,11,20,21])),"/activities/verify":()=>t(()=>import(`./Verify-Bs3lmkTP.js`),__vite__mapDeps([22,1,2,3,4,5,6,18,19,11,20,23])),"/activities/blacklist":()=>t(()=>import(`./Blacklist-D37pxhFr.js`),__vite__mapDeps([24,1,2,3,4,5,6,19,25])),"/ticket-grab-events":()=>t(()=>import(`./TicketGrabList-BU_pQuqX.js`),__vite__mapDeps([26,1,2,3,4,5,6,9,10,15,11,12,27])),"/ticket-grab-events/registrations":()=>t(()=>import(`./TicketGrabRegistrations-C9INxLtz.js`),__vite__mapDeps([28,2,3,5,18,19,11,20])),"/ticket-grab-events/verify":()=>t(()=>import(`./TicketGrabVerify-DGmDGWxl.js`),__vite__mapDeps([29,1,2,3,4,5,6,18,19,11,20,30])),"/study-tours":()=>t(()=>import(`./StudyTourList-BOSu3Fqc.js`),__vite__mapDeps([31,1,2,3,4,5,6,9,10,11,12,32])),"/traffic":()=>t(()=>import(`./Monitor-CwQryTgE.js`),__vite__mapDeps([33,3,34])),"/traffic/leaderboard":()=>t(()=>import(`./Leaderboard-DpnW60sP.js`),__vite__mapDeps([35,3,34])),"/traffic/alerts":()=>t(()=>import(`./Alerts-CLB4PUbf.js`),__vite__mapDeps([36,3,34])),"/stats":()=>t(()=>import(`./Overview-DWCg_gXr.js`),__vite__mapDeps([37,3,34])),"/stats/regions":()=>t(()=>import(`./Regions-wTSahatX.js`),__vite__mapDeps([38,3,34])),"/stats/categories":()=>t(()=>import(`./Categories-C4UExwsU.js`),__vite__mapDeps([39,3,34])),"/stats/exports":()=>t(()=>import(`./Exports-B2d1jnIW.js`),__vite__mapDeps([40,3,34])),"/system/admins":()=>t(()=>import(`./Admins-DC1D747T.js`),__vite__mapDeps([41,2,3,5,11])),"/system/roles":()=>t(()=>import(`./Roles-DV332Q28.js`),__vite__mapDeps([42,1,2,3,4,5,6])),"/system/menus":()=>t(()=>import(`./Menus-Di_lr0wY.js`),__vite__mapDeps([43,1,2,3,4,5,6,44])),"/system/audit-logs":()=>t(()=>import(`./AuditLogs-CcyNcN17.js`),__vite__mapDeps([45,1,2,3,4,5,6,19,11,46])),"/settings/wechat":()=>t(()=>import(`./Wechat-GC1DNCzj.js`),__vite__mapDeps([47,3,34])),"/settings/map":()=>t(()=>import(`./Map-CE8rUj1i.js`),__vite__mapDeps([48,1,2,3,4,5,6])),"/settings/notifications":()=>t(()=>import(`./Notifications-CnFkl2pO.js`),__vite__mapDeps([49,3,34])),"/settings/system-logs":()=>t(()=>import(`./SystemLogs-7whmFJAk.js`),__vite__mapDeps([50,1,2,3,4,5,6,19,51])),"/settings/dictionaries":()=>t(()=>import(`./Dictionaries-Cq9OnVyA.js`),__vite__mapDeps([52,2,3,5])),"/wechat-users":()=>t(()=>import(`./WechatUsers-CslkSm73.js`),__vite__mapDeps([53,2,3,5,11]))};function r(e){let t=[],n=e=>{for(let r of e){let e=r?.path?.trim();e&&t.push(e),Array.isArray(r?.children)&&n(r.children)}};return n(e),t}function i(e){let t=e.trim().replace(/\/+$/,``)||`/`;return t.startsWith(`/`)?t:`/${t}`}function a(e){if(e.size===0)return`/dashboard`;for(let t of[`/dashboard`,`/activities`,`/venues`,`/wechat-users`])if(e.has(t))return t;return[...e].sort()[0]??`/dashboard`}var o=null,s=!1;function c(){return o}async function l(){try{let{data:t}=await e.get(`/admin-menus`),n=r(Array.isArray(t)?t:[]);return a(new Set(n.map(e=>i(e))))}catch{return`/dashboard`}}async function u(t){if(s)return;let{data:a}=await e.get(`/admin-menus`),c=r(Array.isArray(a)?a:[]);o=new Set(c.map(e=>i(e)));for(let e of c){let r=i(e).replace(/\/$/,``)||`/`,a=n[r];if(!a)continue;let o=r.startsWith(`/`)?r.slice(1):r,s=`dyn-${o.replace(/\//g,`-`)}`;t.hasRoute(s)||t.addRoute(`admin-layout`,{path:o,name:s,component:a})}s=!0}function d(e){o=null,s=!1;for(let t of e.getRoutes()){let n=t.name?.toString()??``;n.startsWith(`dyn-`)&&e.removeRoute(n)}}function f(){return s}export{a,f as i,c as n,u as o,l as r,d as s,r as t};
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Dashboard-B1oSG5Zd.js","assets/index-DHqNSBjF.js","assets/axios-CiYFffbI.js","assets/runtime-core.esm-bundler-CnFWH3R5.js","assets/preload-helper-BIjWqNH5.js","assets/http-LCi9aT1G.js","assets/index-C6I69YBI.css","assets/Dashboard-D_6tkjXe.css","assets/VenueList-DElrrOC2.js","assets/RichEditorField-TpmK0B1t.js","assets/RichEditorField-BSoIk7uU.css","assets/listTableRowIndex-Bl-nc9Qt.js","assets/mediaUrl-CPV6u7br.js","assets/VenueList-WvFrBNwX.css","assets/ActivityList-DmfNwGyI.js","assets/h5Http-2MvWKf2X.js","assets/ActivityList-CiEwR7bO.css","assets/Registrations-DyS1qADt.js","assets/bookingType-sDQIPutU.js","assets/datetime-DLy52ZIc.js","assets/reservationStatus-DPnogIlu.js","assets/Registrations-YJz5wXb8.css","assets/Verify-Do4xxfry.js","assets/Verify-Dw49jI2o.css","assets/Blacklist-I3-qIS-y.js","assets/Blacklist-CtQQ6LfC.css","assets/TicketGrabList-CpQCmVxF.js","assets/TicketGrabList-YiBC5xvV.css","assets/TicketGrabRegistrations-CA7bnaSZ.js","assets/TicketGrabVerify-DwVqezQF.js","assets/TicketGrabVerify-C99ifrCo.css","assets/StudyTourList-BORUYDJ4.js","assets/StudyTourList-S9h38Ufv.css","assets/Monitor-CwQryTgE.js","assets/PagePlaceholder-Cy4-OO0C.js","assets/Leaderboard-DpnW60sP.js","assets/Alerts-CLB4PUbf.js","assets/Overview-DWCg_gXr.js","assets/Regions-wTSahatX.js","assets/Categories-C4UExwsU.js","assets/Exports-B2d1jnIW.js","assets/Admins-D7Ypk5Yw.js","assets/Roles-BmP0dRtz.js","assets/Menus-1InLvK3n.js","assets/Menus-CIRuEnr6.css","assets/AuditLogs-MobpSdO4.js","assets/AuditLogs-Bd90uV6l.css","assets/Wechat-GC1DNCzj.js","assets/Map-B4BBukvN.js","assets/Notifications-CnFkl2pO.js","assets/SystemLogs-NtssejDv.js","assets/SystemLogs-DSVhElsT.css","assets/Dictionaries-Cq9OnVyA.js","assets/WechatUsers-CslkSm73.js"])))=>i.map(i=>d[i]);
import{n as e}from"./http-LCi9aT1G.js";import{t}from"./preload-helper-BIjWqNH5.js";var n={"/dashboard":()=>t(()=>import(`./Dashboard-B1oSG5Zd.js`),__vite__mapDeps([0,1,2,3,4,5,6,7])),"/venues":()=>t(()=>import(`./VenueList-DElrrOC2.js`),__vite__mapDeps([8,1,2,3,4,5,6,9,10,11,12,13])),"/activities":()=>t(()=>import(`./ActivityList-DmfNwGyI.js`),__vite__mapDeps([14,1,2,3,4,5,6,9,10,15,11,16])),"/activities/registrations":()=>t(()=>import(`./Registrations-DyS1qADt.js`),__vite__mapDeps([17,1,2,3,4,5,6,18,19,11,20,21])),"/activities/verify":()=>t(()=>import(`./Verify-Do4xxfry.js`),__vite__mapDeps([22,1,2,3,4,5,6,18,19,11,20,23])),"/activities/blacklist":()=>t(()=>import(`./Blacklist-I3-qIS-y.js`),__vite__mapDeps([24,1,2,3,4,5,6,19,25])),"/ticket-grab-events":()=>t(()=>import(`./TicketGrabList-CpQCmVxF.js`),__vite__mapDeps([26,1,2,3,4,5,6,9,10,15,11,12,27])),"/ticket-grab-events/registrations":()=>t(()=>import(`./TicketGrabRegistrations-CA7bnaSZ.js`),__vite__mapDeps([28,2,3,5,18,19,11,20])),"/ticket-grab-events/verify":()=>t(()=>import(`./TicketGrabVerify-DwVqezQF.js`),__vite__mapDeps([29,1,2,3,4,5,6,18,19,11,20,30])),"/study-tours":()=>t(()=>import(`./StudyTourList-BORUYDJ4.js`),__vite__mapDeps([31,1,2,3,4,5,6,9,10,11,12,32])),"/traffic":()=>t(()=>import(`./Monitor-CwQryTgE.js`),__vite__mapDeps([33,3,34])),"/traffic/leaderboard":()=>t(()=>import(`./Leaderboard-DpnW60sP.js`),__vite__mapDeps([35,3,34])),"/traffic/alerts":()=>t(()=>import(`./Alerts-CLB4PUbf.js`),__vite__mapDeps([36,3,34])),"/stats":()=>t(()=>import(`./Overview-DWCg_gXr.js`),__vite__mapDeps([37,3,34])),"/stats/regions":()=>t(()=>import(`./Regions-wTSahatX.js`),__vite__mapDeps([38,3,34])),"/stats/categories":()=>t(()=>import(`./Categories-C4UExwsU.js`),__vite__mapDeps([39,3,34])),"/stats/exports":()=>t(()=>import(`./Exports-B2d1jnIW.js`),__vite__mapDeps([40,3,34])),"/system/admins":()=>t(()=>import(`./Admins-D7Ypk5Yw.js`),__vite__mapDeps([41,2,3,5,11])),"/system/roles":()=>t(()=>import(`./Roles-BmP0dRtz.js`),__vite__mapDeps([42,1,2,3,4,5,6])),"/system/menus":()=>t(()=>import(`./Menus-1InLvK3n.js`),__vite__mapDeps([43,1,2,3,4,5,6,44])),"/system/audit-logs":()=>t(()=>import(`./AuditLogs-MobpSdO4.js`),__vite__mapDeps([45,1,2,3,4,5,6,19,11,46])),"/settings/wechat":()=>t(()=>import(`./Wechat-GC1DNCzj.js`),__vite__mapDeps([47,3,34])),"/settings/map":()=>t(()=>import(`./Map-B4BBukvN.js`),__vite__mapDeps([48,1,2,3,4,5,6])),"/settings/notifications":()=>t(()=>import(`./Notifications-CnFkl2pO.js`),__vite__mapDeps([49,3,34])),"/settings/system-logs":()=>t(()=>import(`./SystemLogs-NtssejDv.js`),__vite__mapDeps([50,1,2,3,4,5,6,19,51])),"/settings/dictionaries":()=>t(()=>import(`./Dictionaries-Cq9OnVyA.js`),__vite__mapDeps([52,2,3,5])),"/wechat-users":()=>t(()=>import(`./WechatUsers-CslkSm73.js`),__vite__mapDeps([53,2,3,5,11]))};function r(e){let t=[],n=e=>{for(let r of e){let e=r?.path?.trim();e&&t.push(e),Array.isArray(r?.children)&&n(r.children)}};return n(e),t}function i(e){let t=e.trim().replace(/\/+$/,``)||`/`;return t.startsWith(`/`)?t:`/${t}`}function a(e){if(e.size===0)return`/dashboard`;for(let t of[`/dashboard`,`/activities`,`/venues`,`/wechat-users`])if(e.has(t))return t;return[...e].sort()[0]??`/dashboard`}var o=null,s=!1;function c(){return o}async function l(){try{let{data:t}=await e.get(`/admin-menus`),n=r(Array.isArray(t)?t:[]);return a(new Set(n.map(e=>i(e))))}catch{return`/dashboard`}}async function u(t){if(s)return;let{data:a}=await e.get(`/admin-menus`),c=r(Array.isArray(a)?a:[]);o=new Set(c.map(e=>i(e)));for(let e of c){let r=i(e).replace(/\/$/,``)||`/`,a=n[r];if(!a)continue;let o=r.startsWith(`/`)?r.slice(1):r,s=`dyn-${o.replace(/\//g,`-`)}`;t.hasRoute(s)||t.addRoute(`admin-layout`,{path:o,name:s,component:a})}s=!0}function d(e){o=null,s=!1;for(let t of e.getRoutes()){let n=t.name?.toString()??``;n.startsWith(`dyn-`)&&e.removeRoute(n)}}function f(){return s}export{a,f as i,c as n,u as o,l as r,d as s,r as t};

@ -0,0 +1 @@
import{t as e}from"./axios-CiYFffbI.js";var t=`szkp_h5_verify_token`,n=`szkp_verify_portal_code`,r=`szkp_verify_portal_legacy_token`,i=`szkp_verify_auth_mode`,a=`https://szkp-map.langye.net/api`;function o(){let e=(window.location.pathname||``).includes(`/m/verify`)?`m/verify/login`:`h5/verify/login`,t=`/admin/`,n=t.endsWith(`/`)?t:`${t}/`;return`${window.location.origin}${n}${e}`}var s=e.create({baseURL:a,timeout:2e4});s.interceptors.request.use(e=>{let n=localStorage.getItem(t);return n&&(e.headers.Authorization=`Bearer ${n}`),e}),s.interceptors.response.use(e=>e,e=>{let n=e?.response?.status;if(n===401||n===403){localStorage.removeItem(t);let e=window.location.pathname||``;(e.includes(`/h5/verify`)||e.includes(`/m/verify`))&&window.location.replace(o())}return Promise.reject(e)});export{o as a,r as i,i as n,s as o,n as r,t};

@ -1 +0,0 @@
import{t as e}from"./axios-CiYFffbI.js";var t=`szkp_h5_verify_token`,n=`szkp_verify_portal_code`,r=`szkp_verify_portal_legacy_token`,i=`szkp_verify_auth_mode`,a=`https://szkp-map.langye.net/api`;function o(){let e=localStorage.getItem(n),t=localStorage.getItem(r),i=(window.location.pathname||``).includes(`/m/verify`)?`m/verify/login`:`h5/verify/login`,a=`/admin/`,o=a.endsWith(`/`)?a:`${a}/`,s=new URL(`${window.location.origin}${o}${i}`);return e?s.searchParams.set(`v`,e):t&&s.searchParams.set(`portal`,t),s.toString()}function s(e){let t=`/admin/`,n=t.endsWith(`/`)?t:`${t}/`,r=new URL(`${window.location.origin}${n}h5/verify/login`);return r.searchParams.set(`v`,String(e).toLowerCase().trim()),r.toString()}var c=e.create({baseURL:a,timeout:2e4});c.interceptors.request.use(e=>{let n=localStorage.getItem(t);return n&&(e.headers.Authorization=`Bearer ${n}`),e}),c.interceptors.response.use(e=>e,e=>{let n=e?.response?.status;if(n===401||n===403){localStorage.removeItem(t);let e=window.location.pathname||``;(e.includes(`/h5/verify`)||e.includes(`/m/verify`))&&window.location.replace(o())}return Promise.reject(e)});export{s as a,r as i,i as n,c as o,n as r,t};

File diff suppressed because one or more lines are too long

@ -5,12 +5,12 @@
<link rel="icon" type="image/svg+xml" href="/admin/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>苏州市科普场馆地图后台管理系统</title>
<script type="module" crossorigin src="/admin/assets/index-B-4Rg8Jl.js"></script>
<script type="module" crossorigin src="/admin/assets/index-DHqNSBjF.js"></script>
<link rel="modulepreload" crossorigin href="/admin/assets/runtime-core.esm-bundler-CnFWH3R5.js">
<link rel="modulepreload" crossorigin href="/admin/assets/axios-CiYFffbI.js">
<link rel="modulepreload" crossorigin href="/admin/assets/preload-helper-BIjWqNH5.js">
<link rel="modulepreload" crossorigin href="/admin/assets/http-LCi9aT1G.js">
<link rel="modulepreload" crossorigin href="/admin/assets/dynamicAdminRoutes-Bp7nHMfT.js">
<link rel="modulepreload" crossorigin href="/admin/assets/dynamicAdminRoutes-BAMeDyVx.js">
<link rel="stylesheet" crossorigin href="/admin/assets/index-C6I69YBI.css">
</head>
<body>

@ -152,6 +152,7 @@ Route::middleware(['auth:sanctum', 'audit.log'])->group(function () {
Route::put('/activities/{activity}/behind-scenes', [ActivityController::class, 'updateBehindScenes']);
Route::post('/activities/{activity}/hot-flag', [ActivityController::class, 'setHotFlag']);
Route::post('/activities/{activity}/audit/reject', [ActivityController::class, 'reject']);
Route::get('/activities/{activity}/activity-audit-logs', [ActivityController::class, 'auditLogs']);
Route::post('/activities/{activity}/toggle', [ActivityController::class, 'toggle']);
Route::delete('/activities/{activity}', [ActivityController::class, 'destroy']);
Route::post('/activities/{activity}/restore', [ActivityController::class, 'restore']);

Loading…
Cancel
Save