feat: 扩展奖池、风控与报表能力,新增对账补偿、广播和人工操作接口
This commit is contained in:
@@ -12,12 +12,17 @@ use App\Services\AuditLogger;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Support\OddsStandardScopes;
|
||||
use App\Lottery\ConfigVersionStatus;
|
||||
use App\Services\Draw\LotteryHallRealtimeBroadcaster;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
|
||||
/** 后台:赔率版本({@see odds_versions} / {@see odds_items}) */
|
||||
final class OddsStreamService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly LotteryHallRealtimeBroadcaster $hallRealtime,
|
||||
) {}
|
||||
|
||||
/** @return LengthAwarePaginator<int, OddsVersion> */
|
||||
public function paginate(?string $status, int $perPage, int $page = 1): LengthAwarePaginator
|
||||
{
|
||||
@@ -138,6 +143,11 @@ final class OddsStreamService
|
||||
});
|
||||
|
||||
$after = $this->snapshotVersion($draft->fresh(['items']));
|
||||
$this->hallRealtime->notifyOddsUpdate(
|
||||
(int) $draft->id,
|
||||
'v'.(string) $draft->version_no,
|
||||
['version_no' => (int) $draft->version_no],
|
||||
);
|
||||
|
||||
AuditLogger::recordForAdmin(
|
||||
$admin,
|
||||
|
||||
@@ -10,12 +10,17 @@ use App\Models\PlayConfigItem;
|
||||
use App\Models\PlayConfigVersion;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Lottery\ConfigVersionStatus;
|
||||
use App\Services\Draw\LotteryHallRealtimeBroadcaster;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
|
||||
/** 后台:玩法配置版本({@see play_config_versions} / {@see play_config_items}) */
|
||||
final class PlayConfigStreamService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly LotteryHallRealtimeBroadcaster $hallRealtime,
|
||||
) {}
|
||||
|
||||
/** @return LengthAwarePaginator<int, PlayConfigVersion> */
|
||||
public function paginate(?string $status, int $perPage, int $page = 1): LengthAwarePaginator
|
||||
{
|
||||
@@ -140,6 +145,12 @@ final class PlayConfigStreamService
|
||||
{
|
||||
$this->validatePublishableDraft($draft);
|
||||
$before = $this->snapshotVersion($draft);
|
||||
$currentItems = PlayConfigItem::query()
|
||||
->whereIn('version_id', PlayConfigVersion::query()
|
||||
->select('id')
|
||||
->where('status', ConfigVersionStatus::Active->value))
|
||||
->get()
|
||||
->keyBy('play_code');
|
||||
|
||||
DB::transaction(function () use ($draft, $admin): void {
|
||||
/** @var PlayConfigVersion|null $current */
|
||||
@@ -160,6 +171,7 @@ final class PlayConfigStreamService
|
||||
});
|
||||
|
||||
$after = $this->snapshotVersion($draft->fresh(['items']));
|
||||
$this->broadcastToggleDiffs($currentItems, $draft->items()->get());
|
||||
|
||||
AuditLogger::recordForAdmin(
|
||||
$admin,
|
||||
@@ -173,6 +185,26 @@ final class PlayConfigStreamService
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Support\Collection<string, PlayConfigItem> $currentItems
|
||||
* @param \Illuminate\Support\Collection<int, PlayConfigItem> $nextItems
|
||||
*/
|
||||
private function broadcastToggleDiffs(\Illuminate\Support\Collection $currentItems, \Illuminate\Support\Collection $nextItems): void
|
||||
{
|
||||
foreach ($nextItems as $next) {
|
||||
$current = $currentItems->get($next->play_code);
|
||||
if ($current === null || (bool) $current->is_enabled === (bool) $next->is_enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->hallRealtime->notifyPlayToggle(
|
||||
(string) $next->play_code,
|
||||
(bool) $next->is_enabled,
|
||||
'play config version published',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteVersion(PlayConfigVersion $version, AdminUser $admin, ?Request $request = null): void
|
||||
{
|
||||
$before = $this->snapshotVersion($version);
|
||||
|
||||
@@ -59,15 +59,13 @@ final class RiskCapStreamService
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
foreach (['0000', '1234', '9999'] as $num) {
|
||||
RiskCapItem::query()->create([
|
||||
'version_id' => $draft->id,
|
||||
'draw_id' => null,
|
||||
'normalized_number' => $num,
|
||||
'cap_amount' => 50_000_000_000,
|
||||
'cap_type' => 'per_number',
|
||||
]);
|
||||
}
|
||||
RiskCapItem::query()->create([
|
||||
'version_id' => $draft->id,
|
||||
'draw_id' => null,
|
||||
'normalized_number' => '0000',
|
||||
'cap_amount' => 50_000_000_000,
|
||||
'cap_type' => 'default',
|
||||
]);
|
||||
}
|
||||
|
||||
return $draft->fresh(['items']);
|
||||
@@ -179,7 +177,10 @@ final class RiskCapStreamService
|
||||
$normalizedNumber = (string) $row->normalized_number;
|
||||
$capAmount = (int) $row->cap_amount;
|
||||
$drawId = $row->draw_id === null ? '__null__' : (string) $row->draw_id;
|
||||
$key = $drawId.'|'.$normalizedNumber;
|
||||
$capType = (string) $row->cap_type;
|
||||
$key = $capType === 'default'
|
||||
? 'default|'.$drawId
|
||||
: $drawId.'|'.$normalizedNumber;
|
||||
|
||||
if (! preg_match('/^[0-9]{4}$/', $normalizedNumber)) {
|
||||
$errors["items.$index.normalized_number"][] = '号码必须是 4 位数字';
|
||||
@@ -189,6 +190,10 @@ final class RiskCapStreamService
|
||||
$errors["items.$index.cap_amount"][] = '封顶金额必须大于 0';
|
||||
}
|
||||
|
||||
if ($capType === 'default' && $row->draw_id !== null) {
|
||||
$errors["items.$index.cap_type"][] = '默认封顶不能绑定具体期号';
|
||||
}
|
||||
|
||||
if (isset($seenKeys[$key])) {
|
||||
$errors["items.$index"][] = '同一期号与号码存在重复封顶配置';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user