[默认值, 最小, 最大];最小为 null 的是字符串。 */ public const KEYS = [ 'simulation_enabled' => ['0', 0, 1], 'simulation_max_concurrency' => ['2', 1, 10], 'simulation_rate_per_minute' => ['30', 1, 120], 'simulation_max_members_per_task' => ['20', 1, 200], 'simulation_max_members_total' => ['500', 1, 5000], 'simulation_max_amount' => ['10000', 1, 1000000], 'simulation_initial_balance' => ['0', 0, 1000000], 'simulation_wager_bypass' => ['1', 0, 1], 'simulation_default_domain' => ['sim.local', null, null], ]; public static function all(): array { $stored = DB::table('config')->whereIn('field', array_keys(self::KEYS))->pluck('val', 'field'); $out = []; foreach (self::KEYS as $key => [$default]) $out[$key] = (string) ($stored[$key] ?? $default); return $out; } public static function get(string $key): string { return self::all()[$key]; } public static function save(array $input): array { $before = self::all(); foreach (self::KEYS as $key => [, $min, $max]) { if (!array_key_exists($key, $input)) continue; $value = trim((string) $input[$key]); if ($min === null) { if ($value === '' || strlen($value) > 100) throw new Exception('域名格式不正确', HttpStatus::CUSTOM_ERROR); } elseif (!is_numeric($value) || $value < $min || $value > $max) { throw new Exception("{$key} 应在 {$min} 到 {$max} 之间", HttpStatus::CUSTOM_ERROR); } $exists = DB::table('config')->where('field', $key)->exists(); if ($exists) DB::table('config')->where('field', $key)->update(['val' => $value]); else DB::table('config')->insert(['field' => $key, 'val' => $value]); } return ['before' => $before, 'after' => self::all()]; } public static function enabled(): bool { return self::get('simulation_enabled') === '1'; } public static function assertEnabled(): void { if (!MemberAudience::enabled()) throw new Exception('用户类型字段尚未迁移,无法使用模拟管理', HttpStatus::CUSTOM_ERROR); if (!self::enabled()) throw new Exception('模拟功能未开启,请先在“模拟设置”中开启', HttpStatus::CUSTOM_ERROR); } /** 写操作的目标必须是后台模拟会员,返回该会员。 */ public static function member($memberId): object { $user = DB::table('users')->where('member_id', (string) $memberId)->where('user_type', MemberAudience::TYPE_SIMULATED)->first(); if (!$user) throw new Exception('只能操作模拟会员', HttpStatus::CUSTOM_ERROR); return $user; } public static function assertAmount($amount): string { if (!is_numeric($amount) || $amount <= 0) throw new Exception('金额格式不正确', HttpStatus::CUSTOM_ERROR); if ($amount > (float) self::get('simulation_max_amount')) throw new Exception('金额超过模拟设置的单次上限', HttpStatus::CUSTOM_ERROR); return number_format((float) $amount, 2, '.', ''); } }