self::getConfigBool(self::KEY_AUTO_CREATE) ? 1 : 0, 'period_manual_create_enabled' => self::getConfigBool(self::KEY_MANUAL_CREATE) ? 1 : 0, ]; } public static function saveRecordSettings(array $data): void { $now = time(); $auto = self::truthyConfigInput($data['period_auto_create_enabled'] ?? null) ? '1' : '0'; $manual = self::truthyConfigInput($data['period_manual_create_enabled'] ?? null) ? '1' : '0'; self::upsertConfig(self::KEY_AUTO_CREATE, $auto, 'int', '是否允许定时任务自动创建下一局(全局仅一局)', $now); self::upsertConfig(self::KEY_MANUAL_CREATE, $manual, 'int', '是否允许后台手动创建下一局', $now); } public static function hasActiveRecord(): bool { $count = Db::name('game_record')->whereIn('status', self::ACTIVE_STATUSES)->count(); return $count > 0; } public static function tickAutoCreate(): void { if (!self::getConfigBool(self::KEY_AUTO_CREATE)) { return; } if (self::hasActiveRecord()) { return; } try { self::createNextRecordRow(); } catch (Throwable) { } } public static function createNextRecordForManual(): array { if (!self::getConfigBool(self::KEY_MANUAL_CREATE)) { return ['ok' => false, 'msg' => __('Manual create next round is disabled')]; } if (self::hasActiveRecord()) { return ['ok' => false, 'msg' => __('There is an unfinished round; cannot create a new one')]; } try { $periodNo = self::createNextRecordRow(); return ['ok' => true, 'msg' => __('New round created'), 'period_no' => $periodNo]; } catch (Throwable $e) { return ['ok' => false, 'msg' => $e->getMessage()]; } } public static function createNextRecordAfterDraw(): ?string { // 派彩结束后是否自动开新局:由 period_auto_create_enabled 控制 if (!self::getConfigBool(self::KEY_AUTO_CREATE)) { return null; } if (self::hasActiveRecord()) { return null; } return self::createNextRecordRow(); } /** * 实时对局页「自动创建下一局」开关(兼容旧命名 runtime)。 */ public static function isLiveRuntimeEnabled(): bool { return self::getConfigBool(self::KEY_AUTO_CREATE); } public static function setLiveRuntimeEnabled(bool $enabled): void { self::setAutoCreateEnabled($enabled); } /** * 重新开启游戏时:若无进行中/未结清对局,则立即创建新一期(与定时任务「无局时自动创建」语义一致,供开关打开时立刻开局)。 */ public static function bootstrapPeriodWhenRuntimeEnabled(): void { if (!self::getConfigBool(self::KEY_AUTO_CREATE)) { return; } if (self::hasActiveRecord()) { return; } try { self::createNextRecordRow(); } catch (Throwable) { } } public static function setAutoCreateEnabled(bool $enabled): void { $now = time(); $v = $enabled ? '1' : '0'; self::upsertConfig(self::KEY_AUTO_CREATE, $v, 'int', '是否允许自动创建下一局(全局仅一局)', $now); } private static function createNextRecordRow(): string { $periodNo = self::generatePeriodNo(); $now = time(); Db::name('game_record')->insert([ 'period_no' => $periodNo, 'period_start_at' => $now, 'status' => 0, 'draw_mode' => 0, 'void_reason' => '', 'create_time' => $now, 'update_time' => $now, ]); GameHotDataCoordinator::afterGameRecordCommitted(null); return $periodNo; } private static function generatePeriodNo(): string { return date('Ymd-His') . '-' . substr(bin2hex(random_bytes(4)), 0, 8); } private static function truthyConfigInput(mixed $v): bool { return $v === 1 || $v === '1' || $v === true; } private static function upsertConfig(string $key, string $value, string $valueType, string $remark, int $now): void { $exists = Db::name('game_config')->where('config_key', $key)->find(); if ($exists) { Db::name('game_config')->where('config_key', $key)->update([ 'config_value' => $value, 'value_type' => $valueType, 'remark' => $remark, 'update_time' => $now, ]); GameHotDataCoordinator::afterGameConfigKeyCommitted($key); return; } Db::name('game_config')->insert([ 'config_key' => $key, 'config_value' => $value, 'value_type' => $valueType, 'remark' => $remark, 'create_time' => $now, 'update_time' => $now, ]); GameHotDataCoordinator::afterGameConfigKeyCommitted($key); } }