You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 lines
4.6 KiB

<?php
namespace App\Http\Controllers\Api\Admin;
use App\Http\Controllers\Controller;
use App\Models\AudienceSmsLog;
use App\Models\Competition;
use App\Services\Sms\AudienceSmsLogService;
use App\Support\BizDateTime;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
class AudienceSmsLogController extends Controller
{
public function index(Request $request, Competition $competition, AudienceSmsLogService $service): JsonResponse
{
$filters = $request->validate([
'page' => ['sometimes', 'integer', 'min:1'],
'per_page' => ['sometimes', 'integer', 'min:1', 'max:100'],
'mobile' => ['sometimes', 'nullable', 'string', 'max:20'],
'status' => ['sometimes', 'nullable', 'string', Rule::in([
'',
AudienceSmsLog::STATUS_PENDING,
AudienceSmsLog::STATUS_SENDING,
AudienceSmsLog::STATUS_DELIVERED,
AudienceSmsLog::STATUS_DROPPED,
AudienceSmsLog::STATUS_FAILED,
])],
'scene' => ['sometimes', 'nullable', 'string', Rule::in([
'',
AudienceSmsLog::SCENE_PRE_REGISTER,
AudienceSmsLog::SCENE_APPROVED,
AudienceSmsLog::SCENE_AUDIENCE_LOGIN,
AudienceSmsLog::SCENE_PARTICIPANT_LOGIN,
])],
]);
$service->syncFromLogApi($competition);
$query = $this->buildQuery($competition, $filters);
$perPage = min((int) ($filters['per_page'] ?? 15), 100);
$paginator = $query->paginate($perPage);
$paginator->getCollection()->transform(fn (AudienceSmsLog $row) => $this->toArray($row));
return response()->json($paginator);
}
public function sync(Competition $competition, AudienceSmsLogService $service): JsonResponse
{
return response()->json($service->syncFromLogApi($competition, true));
}
public function resend(
Competition $competition,
AudienceSmsLog $audience_sms_log,
AudienceSmsLogService $service,
): JsonResponse {
$created = $service->resend($competition, $audience_sms_log);
return response()->json($this->toArray($created));
}
/**
* @param array<string, mixed> $filters
* @return Builder<AudienceSmsLog>
*/
private function buildQuery(Competition $competition, array $filters): Builder
{
$query = AudienceSmsLog::query()
->where('competition_id', $competition->id)
->orderByDesc('sent_at')
->orderByDesc('id');
$mobile = trim((string) ($filters['mobile'] ?? ''));
if ($mobile !== '') {
$query->where('mobile', 'like', '%'.$mobile.'%');
}
$status = trim((string) ($filters['status'] ?? ''));
if ($status === AudienceSmsLog::STATUS_FAILED) {
$query->whereIn('status', [AudienceSmsLog::STATUS_FAILED, AudienceSmsLog::STATUS_DROPPED]);
} elseif ($status !== '') {
$query->where('status', $status);
}
$scene = trim((string) ($filters['scene'] ?? ''));
if ($scene !== '') {
$query->where('scene', $scene);
}
return $query;
}
/**
* @return array<string, mixed>
*/
private function toArray(AudienceSmsLog $row): array
{
return [
'id' => $row->id,
'competition_id' => $row->competition_id,
'audience_registration_id' => $row->audience_registration_id,
'scene' => $row->scene,
'scene_label' => AudienceSmsLog::sceneLabel((string) $row->scene),
'mobile' => $row->mobile,
'template_id' => $row->template_id,
'content' => $row->content,
'send_id' => $row->send_id,
'status' => $row->status,
'status_label' => $this->statusLabel($row->status),
'fee' => $row->fee,
'report_state' => $row->report_state,
'dropped_reason' => $row->dropped_reason,
'can_resend' => $row->canResend(),
'sent_at' => BizDateTime::toIso8601($row->sent_at),
'delivered_at' => BizDateTime::toIso8601($row->delivered_at),
];
}
private function statusLabel(string $status): string
{
return match ($status) {
AudienceSmsLog::STATUS_DELIVERED => '发送成功',
AudienceSmsLog::STATUS_DROPPED, AudienceSmsLog::STATUS_FAILED => '发送失败',
AudienceSmsLog::STATUS_SENDING => '发送中',
default => '待回执',
};
}
}