139 lines
5.3 KiB
PHP
139 lines
5.3 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Admin;
|
|
|
|
use App\Models\Draw;
|
|
use App\Models\RiskPoolLockLog;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Pagination\LengthAwarePaginator;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
/**
|
|
* 风险占用流水查询:按号码明细或按注单聚合。
|
|
*/
|
|
final class AdminRiskPoolLockLogQueryService
|
|
{
|
|
/**
|
|
* @return LengthAwarePaginator<int, object>
|
|
*/
|
|
public function paginateEntries(Draw $draw, Request $request, int $page, int $perPage): LengthAwarePaginator
|
|
{
|
|
$action = trim((string) $request->query('action_type', ''));
|
|
$number = trim((string) $request->query('normalized_number', ''));
|
|
$providerCode = strtoupper(trim((string) $request->query('provider_code', '')));
|
|
$ticketItemId = (int) $request->integer('ticket_item_id', 0);
|
|
|
|
$q = RiskPoolLockLog::query()
|
|
->where('draw_id', $draw->id)
|
|
->with(['ticketItem:id,ticket_no,play_code,player_id'])
|
|
->orderByDesc('created_at')
|
|
->orderByDesc('id');
|
|
|
|
if ($action !== '' && in_array($action, ['lock', 'release'], true)) {
|
|
$q->where('action_type', $action);
|
|
}
|
|
|
|
if ($number !== '' && preg_match('/^[0-9]{4}$/', $number) === 1) {
|
|
$q->where('normalized_number', $number);
|
|
}
|
|
|
|
if ($providerCode !== '') {
|
|
$q->where('provider_code', $providerCode);
|
|
}
|
|
|
|
if ($ticketItemId > 0) {
|
|
$q->where('ticket_item_id', $ticketItemId);
|
|
}
|
|
|
|
return $q->paginate($perPage, ['*'], 'page', $page);
|
|
}
|
|
|
|
/**
|
|
* @return LengthAwarePaginator<int, object>
|
|
*/
|
|
public function paginateByTicket(Draw $draw, Request $request, int $page, int $perPage): LengthAwarePaginator
|
|
{
|
|
$action = trim((string) $request->query('action_type', ''));
|
|
$number = trim((string) $request->query('normalized_number', ''));
|
|
$providerCode = strtoupper(trim((string) $request->query('provider_code', '')));
|
|
$ticketItemId = (int) $request->integer('ticket_item_id', 0);
|
|
|
|
$bindings = ['draw_id' => $draw->id];
|
|
$filters = 'l.draw_id = :draw_id AND l.ticket_item_id IS NOT NULL';
|
|
|
|
if ($action !== '' && in_array($action, ['lock', 'release'], true)) {
|
|
$filters .= ' AND l.action_type = :action_type';
|
|
$bindings['action_type'] = $action;
|
|
}
|
|
|
|
if ($number !== '' && preg_match('/^[0-9]{4}$/', $number) === 1) {
|
|
$filters .= ' AND l.normalized_number = :normalized_number';
|
|
$bindings['normalized_number'] = $number;
|
|
}
|
|
|
|
if ($providerCode !== '') {
|
|
$filters .= ' AND l.provider_code = :provider_code';
|
|
$bindings['provider_code'] = $providerCode;
|
|
}
|
|
|
|
if ($ticketItemId > 0) {
|
|
$filters .= ' AND l.ticket_item_id = :ticket_item_id';
|
|
$bindings['ticket_item_id'] = $ticketItemId;
|
|
}
|
|
|
|
$driver = DB::connection()->getDriverName();
|
|
$lockCountExpr = $driver === 'sqlite'
|
|
? "SUM(CASE WHEN l.action_type = 'lock' THEN 1 ELSE 0 END)"
|
|
: "COUNT(*) FILTER (WHERE l.action_type = 'lock')";
|
|
$releaseCountExpr = $driver === 'sqlite'
|
|
? "SUM(CASE WHEN l.action_type = 'release' THEN 1 ELSE 0 END)"
|
|
: "COUNT(*) FILTER (WHERE l.action_type = 'release')";
|
|
$lockAmountExpr = $driver === 'sqlite'
|
|
? "COALESCE(SUM(CASE WHEN l.action_type = 'lock' THEN l.amount ELSE 0 END), 0)"
|
|
: "COALESCE(SUM(l.amount) FILTER (WHERE l.action_type = 'lock'), 0)";
|
|
$releaseAmountExpr = $driver === 'sqlite'
|
|
? "COALESCE(SUM(CASE WHEN l.action_type = 'release' THEN l.amount ELSE 0 END), 0)"
|
|
: "COALESCE(SUM(l.amount) FILTER (WHERE l.action_type = 'release'), 0)";
|
|
|
|
$aggregateSql = <<<SQL
|
|
SELECT
|
|
COALESCE(NULLIF(ti.provider_code, ''), l.provider_code) AS provider_code,
|
|
l.ticket_item_id AS ticket_item_id,
|
|
ti.ticket_no AS ticket_no,
|
|
ti.play_code AS play_code,
|
|
ti.original_number AS original_number,
|
|
ti.combination_count AS combination_count,
|
|
ti.player_id AS player_id,
|
|
{$lockCountExpr} AS lock_entry_count,
|
|
{$releaseCountExpr} AS release_entry_count,
|
|
{$lockAmountExpr} AS total_lock_amount,
|
|
{$releaseAmountExpr} AS total_release_amount,
|
|
COUNT(DISTINCT l.normalized_number) AS number_count,
|
|
MAX(l.created_at) AS last_at
|
|
FROM risk_pool_lock_logs l
|
|
INNER JOIN ticket_items ti ON ti.id = l.ticket_item_id
|
|
WHERE {$filters}
|
|
GROUP BY COALESCE(NULLIF(ti.provider_code, ''), l.provider_code), l.ticket_item_id, ti.ticket_no, ti.play_code, ti.original_number, ti.combination_count, ti.player_id
|
|
SQL;
|
|
|
|
$countSql = "SELECT COUNT(*) AS aggregate_count FROM ({$aggregateSql}) AS grouped";
|
|
$total = (int) (DB::selectOne($countSql, $bindings)->aggregate_count ?? 0);
|
|
$lastPage = max(1, (int) ceil($total / $perPage));
|
|
$page = min(max($page, 1), $lastPage);
|
|
$offset = ($page - 1) * $perPage;
|
|
|
|
$items = DB::select(
|
|
"{$aggregateSql} ORDER BY last_at DESC, ticket_item_id DESC LIMIT {$perPage} OFFSET {$offset}",
|
|
$bindings,
|
|
);
|
|
|
|
return new LengthAwarePaginator(
|
|
$items,
|
|
$total,
|
|
$perPage,
|
|
$page,
|
|
['path' => $request->url(), 'query' => $request->query()],
|
|
);
|
|
}
|
|
}
|