find($channelId); if (!$channel) throw new RuntimeException('充值通道不存在'); if ((int)$channel->data_type !== $expectedDataType) { throw new RuntimeException($expectedDataType === 2 ? '请选择提现通道' : '请选择充值通道'); } $groupIds = array_values(array_unique(array_filter(array_map('intval', $groupIds)))); if (!$groupIds) throw new RuntimeException('至少选择一个通道组合'); $groups = RechargeChannelGroup::query()->whereIn('id', $groupIds)->get(); if ($groups->count() !== count($groupIds)) throw new RuntimeException('部分通道组合不存在'); $field = $this->groupField($expectedDataType); foreach ($groups as $group) { if (!in_array((string)$channel->type, (array)$group->{$field}, true)) { throw new RuntimeException("通道组合“{$group->name}”没有包含通道“{$channel->name}”"); } } return [$channel, $groupIds]; } public function formatMany($models): Collection { $models = $models instanceof Collection ? $models : collect($models); if ($models instanceof EloquentCollection) $models->loadMissing('rechargeChannel'); $groupIds = $models->flatMap(fn ($model) => (array)($model->recharge_channel_group_ids ?? [])) ->map(fn ($id) => (int)$id)->filter()->unique()->values(); $groups = RechargeChannelGroup::query()->whereIn('id', $groupIds)->get()->keyBy('id'); return $models->map(fn (Model $model) => $this->formatOne($model, $groups)); } public function formatOne(Model $model, ?Collection $groups = null): array { $model->loadMissing('rechargeChannel'); $groups ??= RechargeChannelGroup::query() ->whereIn('id', (array)($model->recharge_channel_group_ids ?? []))->get()->keyBy('id'); $channel = $model->rechargeChannel; $assignedIds = array_values(array_unique(array_filter(array_map( 'intval', (array)($model->recharge_channel_group_ids ?? []) )))); $effectiveIds = []; $unavailableIds = []; $groupRows = []; foreach ($assignedIds as $groupId) { $group = $groups->get($groupId); $effective = false; if ($group && $channel) { $effective = in_array( (string)$channel->type, (array)$group->{$this->groupField((int)$channel->data_type)}, true ); } if ($effective) { $effectiveIds[] = $groupId; } else { $unavailableIds[] = $groupId; } $groupRows[] = [ 'id' => $groupId, 'name' => (string)($group->name ?? ''), 'effective' => $effective ? 1 : 0, ]; } $data = $model->toArray(); $data['recharge_channel_group_ids'] = $assignedIds; $data['effective_group_ids'] = $effectiveIds; $data['unavailable_group_ids'] = $unavailableIds; $data['groups'] = $groupRows; $data['recharge_channel'] = $channel ? [ 'id' => (int)$channel->id, 'data_type' => (int)$channel->data_type, 'name' => (string)$channel->name, 'key' => (string)$channel->key, 'type' => (string)$channel->type, 'rate' => number_format((float)$channel->rate, 4, '.', ''), 'fee_rate' => bcmul((string)$channel->rate, '100', 4), 'min_amount' => $channel->min === null ? null : number_format((float)$channel->min, 2, '.', ''), 'max_amount' => $channel->max === null ? null : number_format((float)$channel->max, 2, '.', ''), 'fixed_amounts' => $channel->fixed ?: [], 'sort' => (int)$channel->sort, 'status' => (int)$channel->status, ] : null; $data['fee_rate'] = $channel ? bcmul((string)$channel->rate, '100', 4) : null; $data['min_amount'] = $channel?->min; $data['max_amount'] = $channel?->max; $data['sort'] = $channel ? (int)$channel->sort : null; $data['config_status'] = (int)$model->status; $data['channel_status'] = $channel ? (int)$channel->status : 0; $data['runtime_channel_available'] = $channel && (int)$channel->status === 1 && count($effectiveIds) > 0 ? 1 : 0; $data['effective_status'] = (int)$model->status === 1 && $data['runtime_channel_available'] === 1 ? 1 : 0; if (array_key_exists('amount', $data)) { $data['actual_amount'] = $channel ? bcsub((string)$model->amount, bcmul((string)$model->amount, (string)$channel->rate, 6), 2) : null; } $data['channel_fields_readonly'] = [ 'recharge_channel.name', 'recharge_channel.key', 'recharge_channel.type', 'fee_rate', 'min_amount', 'max_amount', 'recharge_channel.fixed_amounts', 'sort', 'channel_status', ]; unset($data['level_scope']); return $data; } private function groupField(int $dataType): string { return match ($dataType) { 2 => 'withdraw_type', 3 => 'activity_type', default => 'recharge_type', }; } }