*/ private const SKIP_KEYS = ['commitment_accepted', 'plan', 'supporting', 'promise_signature']; /** @var list */ private const SKIP_TYPES = ['file']; /** @var list */ private const AUDIENCE_COLUMNS = ['name', 'phone', 'company', 'job', 'purpose']; /** * @param list|null $schemaJson * @return list}> */ public static function fields(?array $schemaJson): array { if (! is_array($schemaJson)) { return []; } $out = []; foreach ($schemaJson as $row) { if (! is_array($row)) { continue; } $key = trim((string) ($row['key'] ?? '')); $type = trim((string) ($row['type'] ?? '')); if ($key === '' || in_array($key, self::SKIP_KEYS, true) || in_array($type, self::SKIP_TYPES, true)) { continue; } $label = trim((string) ($row['label'] ?? $key)); $options = []; if (($row['options'] ?? null) && is_array($row['options'])) { foreach ($row['options'] as $opt) { if (! is_array($opt)) { continue; } $value = trim((string) ($opt['value'] ?? '')); if ($value === '') { continue; } $options[] = [ 'value' => $value, 'label' => trim((string) ($opt['label'] ?? $value)), ]; } } $out[] = [ 'key' => $key, 'type' => $type !== '' ? $type : 'text', 'label' => $label !== '' ? $label : $key, 'list' => ($row['list'] ?? false) === true, 'filter' => ($row['filter'] ?? false) === true, 'options' => $options, ]; } return $out; } /** * @param list|null $schemaJson * @return list}> */ public static function listFields(?array $schemaJson): array { return array_values(array_filter(self::fields($schemaJson), fn (array $f) => $f['list'])); } /** * @param list|null $schemaJson * @return list}> */ public static function filterFields(?array $schemaJson): array { return array_values(array_filter( self::fields($schemaJson), fn (array $f) => $f['filter'] && ($f['type'] === 'select' || in_array($f['key'], ['track', 'purpose'], true)) )); } /** * 管理端筛选项(中文标签);赛道/场次补全选项。 * * @return list}> */ public static function adminFilterFields(Competition $competition, string $purpose = 'signup'): array { $schema = $purpose === 'audience' ? ($competition->audienceFormSchema?->schema_json) : ($competition->formSchema?->schema_json); $fields = self::filterFields(is_array($schema) ? $schema : null); $out = []; foreach ($fields as $field) { $options = $field['options']; if ($field['key'] === 'track') { if ($options === []) { $competition->loadMissing('tracks'); foreach ($competition->tracks as $track) { $options[] = [ 'value' => (string) $track->track_code, 'label' => (string) $track->title, ]; } } $hasOther = false; foreach ($options as $opt) { if (($opt['value'] ?? '') === SignupDisplay::TRACK_OTHER_CODE) { $hasOther = true; break; } } if (! $hasOther) { $options[] = [ 'value' => SignupDisplay::TRACK_OTHER_CODE, 'label' => '其他', ]; } } if ($purpose === 'audience' && $field['key'] === 'audience_session_id' && $options === []) { $competition->loadMissing('audienceSessions'); foreach ($competition->audienceSessions as $session) { $options[] = [ 'value' => (string) $session->id, 'label' => (string) $session->name, ]; } } $out[] = [ 'key' => $field['key'], 'type' => $field['type'], 'label' => $field['label'], 'options' => $options, ]; } return $out; } /** * @return list */ public static function adminListFields(Competition $competition, string $purpose = 'signup'): array { $schema = $purpose === 'audience' ? ($competition->audienceFormSchema?->schema_json) : ($competition->formSchema?->schema_json); $out = []; foreach (self::listFields(is_array($schema) ? $schema : null) as $field) { $out[] = [ 'key' => $field['key'], 'type' => $field['type'], 'label' => $field['label'], ]; } return $out; } /** * @param array $filters */ public static function extractFilterValues(Request $request, Competition $competition, string $purpose = 'signup'): array { $out = []; foreach (self::adminFilterFields($competition, $purpose) as $field) { $key = $field['key']; if (! $request->exists($key)) { continue; } $value = trim((string) $request->input($key)); if ($value !== '') { $out[$key] = $value; } } return $out; } /** * @param Builder<\App\Models\Application|\App\Models\AudienceRegistration> $query * @param array $filters * @param list $alreadyApplied */ public static function applyFilters( Builder $query, Competition $competition, array $filters, string $purpose = 'signup', array $alreadyApplied = ['track', 'event_location', 'purpose'], ): void { $schema = $purpose === 'audience' ? ($competition->audienceFormSchema?->schema_json) : ($competition->formSchema?->schema_json); $columnKeys = $purpose === 'audience' ? array_flip(self::AUDIENCE_COLUMNS) : array_flip(SignupApplicationFieldRegistry::scalarColumnKeys()); $skip = array_flip($alreadyApplied); foreach (self::filterFields(is_array($schema) ? $schema : null) as $field) { $key = $field['key']; if (isset($skip[$key])) { continue; } $value = trim((string) ($filters[$key] ?? '')); if ($value === '') { continue; } if ($purpose === 'signup' && in_array($key, ['degree', 'location_country', 'event_location'], true)) { $value = SignupOptionCatalog::normalize($key, $value) ?: $value; } if ($purpose === 'audience' && $key === 'purpose') { $value = SignupOptionCatalog::normalize('purpose', $value) ?: $value; } if (isset($columnKeys[$key])) { $query->where($key, $value); } else { $query->where('answers_json->'.$key, $value); } } } /** * @return array */ public static function applicationDisplayMap(Competition $competition, Application $app): array { $competition->loadMissing('formSchema'); $schema = $competition->formSchema?->schema_json; $schemaArr = is_array($schema) ? $schema : null; $out = []; foreach (self::listFields($schemaArr) as $field) { $out[$field['key']] = SignupDisplay::applicationFieldLabel($competition, $app, $field['key'], $schemaArr); } return $out; } /** * @return array */ public static function audienceDisplayMap(Competition $competition, AudienceRegistration $row): array { $competition->loadMissing('audienceFormSchema'); $schema = $competition->audienceFormSchema?->schema_json; $schemaArr = is_array($schema) ? $schema : null; $locale = SignupDisplay::audienceLocale((int) $row->user_id, (int) $row->competition_id); $out = []; foreach (self::listFields($schemaArr) as $field) { $key = $field['key']; $raw = SignupDisplay::audienceFieldValue($row, $key); $value = is_scalar($raw) ? trim((string) $raw) : ''; if ($value === '') { $out[$key] = ''; continue; } if ($key === 'purpose') { $out[$key] = SignupDisplay::purposeLabel($value, $locale); continue; } $fieldDef = LocalizedSchema::fieldByKey($schemaArr, $key); if ($fieldDef !== null && ($fieldDef['type'] ?? '') === 'select') { $out[$key] = LocalizedSchema::optionLabelForValue($fieldDef, $value, $locale); continue; } $out[$key] = $value; } return $out; } }