master
lion 2 days ago
parent f3b9724ee4
commit 274d6e4a48

@ -3,6 +3,8 @@ APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
# 与活动预约开放窗口等业务日期时间一致(数据库 datetime 按本地时刻存储时使用)
APP_TIMEZONE=Asia/Shanghai
SANCTUM_STATEFUL_DOMAINS=localhost:5173,127.0.0.1:5173,localhost:5174,127.0.0.1:5174,localhost,127.0.0.1
CORS_ALLOWED_ORIGINS=http://localhost:5173,http://127.0.0.1:5173,http://localhost:5174,http://127.0.0.1:5174
CORS_SUPPORTS_CREDENTIALS=true

@ -104,7 +104,7 @@ class ActivityRegistrationController extends Controller
return response()->streamDownload(function () use ($rows) {
$out = fopen('php://output', 'w');
fprintf($out, chr(0xEF) . chr(0xBB) . chr(0xBF));
fputcsv($out, ['ID', '活动', '场馆', '报名人', '手机号', '身份证', '预约票数', '预约入馆日期', '状态', '预约时间', '核销时间', '二维码Token']);
fputcsv($out, ['ID', '活动', '场馆', '报名人', '手机号', '身份证', '预约类型', '预约票数', '预约入馆日期', '状态', '预约时间', '核销时间', '二维码Token']);
foreach ($rows as $row) {
$entryDate = $row->activityDay?->activity_date;
$entryDateStr = $entryDate ? Carbon::parse($entryDate)->timezone('Asia/Shanghai')->format('Y-m-d') : '';
@ -115,6 +115,7 @@ class ActivityRegistrationController extends Controller
$row->visitor_name,
$row->visitor_phone ?? '',
$row->id_card ?? '',
self::bookingTypeLabel($row->booking_type, $row->ticket_count),
(string) ($row->ticket_count ?? 1),
$entryDateStr,
self::statusLabel($row->status),
@ -217,4 +218,17 @@ class ActivityRegistrationController extends Controller
default => $status,
};
}
private static function bookingTypeLabel(?string $bookingType, mixed $ticketCount): string
{
if ($bookingType === 'group') {
return '团体';
}
if ($bookingType === 'individual') {
return '个人';
}
$n = max(1, (int) $ticketCount);
return $n > 1 ? '团体' : '个人';
}
}

@ -115,26 +115,34 @@ class H5ReservationController extends Controller
[$bookingType, $peopleCount] = $this->resolveBookingTypeAndPeopleCount($mode, $data, $minPeople, $maxPeople);
$reservation = DB::transaction(function () use ($request, $activity, $day, $data, $peopleCount, $bookingType) {
$wechatUser = $this->authWechatUser($request);
$reservation = DB::transaction(function () use ($activity, $day, $data, $peopleCount, $bookingType, $wechatUser) {
$day->refresh();
$available = (int) $day->day_quota - (int) $day->booked_count;
if ($available < $peopleCount) {
throw ValidationException::withMessages(['activity_day_id' => ['该日期余票不足']]);
}
// 去重规则:同活动同活动日同手机号只能预约一单(未取消)
$dupByPhone = Reservation::query()
// 去重:同一活动、同一活动日,同一用户只能有一单未取消预约(取消后可再约)
// — 按手机号;已登录时同时按微信用户,避免换手机号重复占坑
$dup = Reservation::query()
->where('activity_id', $activity->id)
->where('activity_day_id', $day->id)
->where('visitor_phone', $data['visitor_phone'])
->where('status', '!=', 'cancelled')
->where(function ($q) use ($data, $wechatUser) {
$q->where('visitor_phone', $data['visitor_phone']);
if ($wechatUser) {
$q->orWhere('wechat_user_id', $wechatUser->id);
}
})
->exists();
if ($dupByPhone) {
throw ValidationException::withMessages(['visitor_phone' => ['该手机号在该活动日期已预约过']]);
if ($dup) {
throw ValidationException::withMessages([
'activity_day_id' => ['您在该活动该日期已有未取消的预约,请先取消原预约后再预约'],
]);
}
$wechatUser = $this->authWechatUser($request);
$row = Reservation::create([
'venue_id' => $activity->venue_id,
'activity_id' => $activity->id,

@ -70,7 +70,7 @@ return [
|
*/
'timezone' => 'UTC',
'timezone' => env('APP_TIMEZONE', 'Asia/Shanghai'),
/*
|--------------------------------------------------------------------------

Loading…
Cancel
Save