'充值赠送配置未初始化,请先完成系统更新']); } private function channel($type): string { Validator::make(['channel_type' => $type], ['channel_type' => ['required', 'string', 'max:100']])->validate(); if (!RechargeChannel::where('data_type', 1)->where('type', $type)->exists()) throw ValidationException::withMessages(['channel_type' => '充值方式不存在']); return $type; } private function texts(array $texts): array { $rules = []; $messages = []; foreach (['zh' => '中文', 'en' => '英文', 'vi' => '越南文'] as $lang => $label) { $rules[$lang] = ['required', 'array:text']; $rules[$lang . '.text'] = ['required', 'string', 'max:100']; $messages[$lang . '.required'] = $label . '角标文字不能为空'; $messages[$lang . '.text.required'] = $label . '角标文字不能为空'; } $result = Validator::make($texts, $rules, $messages)->validate(); foreach ($result as $lang => &$text) { if (preg_replace('/[\s\p{Z}\x{200B}\x{FEFF}]+/u', '', $text['text']) === '') throw ValidationException::withMessages(['translations.' . $lang . '.text' => '角标文字不能为空']); $text['text'] = trim($text['text']); } unset($text); return $result; } public function listing(): array { $this->ready(); $rules = DB::table('recharge_bonuses')->get()->keyBy('channel_type'); $rows = []; foreach (RechargeChannel::where('data_type', 1)->orderBy('sort')->orderBy('id')->get() as $channel) { if (isset($rows[$channel->type])) continue; $rule = $rules[$channel->type] ?? null; $rows[$channel->type] = ['channel_type' => $channel->type, 'channel_name' => $channel->name, 'bonus_percent' => RechargeBonusService::percent($rule->bonus_percent ?? '0'), 'enabled' => (int)($rule->enabled ?? 0), 'translations' => $rule ? json_decode($rule->translations, true) : ['zh' => ['text' => ''], 'en' => ['text' => ''], 'vi' => ['text' => '']]]; } return ['total' => count($rows), 'data' => array_values($rows)]; } public function save(array $input): array { $this->ready(); $data = Validator::make($input, ['channel_type' => ['required', 'string'], 'bonus_percent' => ['required', 'numeric', 'between:0,100', 'regex:/^\d+(\.\d{1,2})?$/'], 'enabled' => ['required', 'integer', 'in:0,1'], 'translations' => ['required', 'array:zh,en,vi']])->validate(); $this->channel($data['channel_type']); $data['translations'] = $this->texts($data['translations']); return DB::transaction(function () use ($data) { $before = DB::table('recharge_bonuses')->where('channel_type', $data['channel_type'])->lockForUpdate()->first(); $now = RechargeBonusService::now(); DB::table('recharge_bonuses')->updateOrInsert(['channel_type' => $data['channel_type']], [ 'bonus_percent' => bcadd((string)$data['bonus_percent'], '0', 2), 'enabled' => $data['enabled'], 'translations' => json_encode($data['translations'], JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR), 'created_at' => $before->created_at ?? $now, 'updated_at' => $now]); OperationAuditService::record('recharge_bonus', null, 'save', (array)$before, $data); return $data; }); } public function status(array $input): array { $this->ready(); $data = Validator::make($input, ['channel_type' => ['required', 'string'], 'enabled' => ['required', 'integer', 'in:0,1']])->validate(); $this->channel($data['channel_type']); return DB::transaction(function () use ($data) { $row = DB::table('recharge_bonuses')->where('channel_type', $data['channel_type'])->lockForUpdate()->first(); if (!$row) throw ValidationException::withMessages(['channel_type' => '请先保存该充值方式的赠送配置']); if ($data['enabled']) $this->texts(json_decode($row->translations, true)); DB::table('recharge_bonuses')->where('channel_type', $data['channel_type'])->update(['enabled' => $data['enabled'], 'updated_at' => RechargeBonusService::now()]); OperationAuditService::record('recharge_bonus', null, 'status', (array)$row, $data); return $data; }); } }