You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

303 lines
11 KiB

5 months ago
<?php
namespace Database\Seeders;
use App\Models\Competition;
use App\Models\FormSchemaDefinition;
1 month ago
use App\Support\SignupFieldI18n;
use App\Support\SignupOptionCatalog;
5 months ago
use Illuminate\Database\Seeder;
/**
* 与选手端 ApplyFormView 字段 key / 校验口径对齐的报名表 schema(purpose=signup)。
*
* 运行:php artisan db:seed --class=CompetitionSignupFormSchemaSeeder
* 可选:SIGNUP_SCHEMA_COMPETITION_ID=1(默认 1)
*/
class CompetitionSignupFormSchemaSeeder extends Seeder
{
public function run(): void
{
$competitionId = (int) env('SIGNUP_SCHEMA_COMPETITION_ID', 1);
$competition = Competition::query()->find($competitionId);
if (! $competition) {
$this->command?->warn("Competition {$competitionId} not found, skip.");
return;
}
$purpose = FormSchemaDefinition::PURPOSE_SIGNUP;
$nextVersion = (int) FormSchemaDefinition::query()
->where('competition_id', $competition->id)
->where('purpose', $purpose)
->max('version') + 1;
$schema = FormSchemaDefinition::query()->create([
'competition_id' => $competition->id,
'purpose' => $purpose,
'name' => '选手端报名表(与 /c/{slug}/apply 一致)',
'version' => $nextVersion,
'schema_json' => $this->schemaJson(),
'is_published' => true,
]);
$competition->update(['form_schema_id' => $schema->id]);
$this->command?->info("Form schema #{$schema->id} (v{$nextVersion}) created and bound to competition #{$competitionId}.");
1 month ago
$audiencePurpose = FormSchemaDefinition::PURPOSE_AUDIENCE;
$audienceVersion = (int) FormSchemaDefinition::query()
->where('competition_id', $competition->id)
->where('purpose', $audiencePurpose)
->max('version') + 1;
$audienceSchema = FormSchemaDefinition::query()->create([
'competition_id' => $competition->id,
'purpose' => $audiencePurpose,
'name' => '观众报名表(默认五项)',
'version' => $audienceVersion,
'schema_json' => $this->audienceSchemaJson(),
'is_published' => true,
]);
$competition->update(['audience_form_schema_id' => $audienceSchema->id]);
$this->command?->info("Audience form schema #{$audienceSchema->id} (v{$audienceVersion}) bound to competition #{$competitionId}.");
5 months ago
}
/**
* @return list<array<string, mixed>>
*/
private function schemaJson(): array
{
1 month ago
$degreeOptions = SignupOptionCatalog::schemaOptions(SignupOptionCatalog::degrees());
$countryOptions = SignupOptionCatalog::schemaOptions(SignupOptionCatalog::locationCountries());
$eventLocationOptions = SignupOptionCatalog::schemaOptions(SignupOptionCatalog::eventLocations());
5 months ago
$provinceOptions = array_map(
fn (string $p) => ['label' => $p, 'value' => $p],
$this->provinceOrder(),
);
1 month ago
return $this->withFieldI18n([
5 months ago
[
1 month ago
'key' => 'project_name',
5 months ago
'type' => 'text',
1 month ago
'label' => '项目名称',
5 months ago
'required' => true,
],
[
1 month ago
'key' => 'player_name',
5 months ago
'type' => 'text',
1 month ago
'label' => '申请人姓名',
5 months ago
'required' => true,
],
[
'key' => 'contact_email',
'type' => 'email',
'label' => '注册邮箱',
'required' => true,
],
[
'key' => 'contact_mobile',
'type' => 'tel',
1 month ago
'label' => '申请人电话',
5 months ago
'required' => true,
],
5 months ago
[
1 month ago
'key' => 'school',
5 months ago
'type' => 'text',
1 month ago
'label' => '毕业院校',
'required' => true,
5 months ago
],
[
1 month ago
'key' => 'degree',
'type' => 'select',
'label' => '最高学历',
5 months ago
'required' => true,
1 month ago
'list' => true,
'filter' => true,
1 month ago
'options' => $degreeOptions,
5 months ago
],
[
'key' => 'track',
'type' => 'select',
1 month ago
'label' => '细分赛道',
5 months ago
'required' => true,
1 month ago
'list' => true,
'filter' => true,
1 month ago
],
[
'key' => 'company_name',
'type' => 'text',
'label' => '企业名称',
'required' => true,
'prefill_from' => 'user.company',
5 months ago
],
[
'key' => 'location_country',
'type' => 'select',
1 month ago
'label' => '项目所在地',
5 months ago
'required' => true,
1 month ago
'list' => true,
'filter' => true,
5 months ago
'options' => $countryOptions,
],
[
'key' => 'location_province',
'type' => 'select',
'label' => '省份',
'required' => false,
'options' => $provinceOptions,
'help' => '选择「中国」时必填',
],
[
'key' => 'location_city',
'type' => 'text',
'label' => '城市',
'required' => false,
'help' => '选择「中国」时填写所在城市',
],
[
'key' => 'oversea_country',
'type' => 'text',
1 month ago
'label' => '所在国',
5 months ago
'required' => false,
'placeholder' => '如:新加坡、日本、美国',
'help' => '选择「海外」时必填',
],
[
1 month ago
'key' => 'event_location',
'type' => 'select',
1 month ago
'label' => '意向参赛地点',
1 month ago
'required' => true,
1 month ago
'list' => true,
'filter' => true,
'options' => $eventLocationOptions,
1 month ago
],
[
'key' => 'team_members',
'type' => 'text',
'label' => '团队成员',
'required' => true,
'placeholder' => '多人请用顿号分隔',
5 months ago
],
2 months ago
[
'key' => 'recommend',
'type' => 'text',
'label' => '推荐方',
'required' => false,
1 month ago
'placeholder' => '单位或推荐人名称',
],
[
'key' => 'intro',
'type' => 'textarea',
'label' => '项目简介',
'required' => true,
'placeholder' => '约200字左右',
2 months ago
],
5 months ago
[
'key' => 'commitment_accepted',
'type' => 'checkbox',
1 month ago
'label' => '参赛承诺书',
5 months ago
'required' => true,
1 month ago
'help' => '请点击按钮打开承诺书全文,阅读后在文末手写签名并点击「确认签署」。',
5 months ago
],
[
'key' => 'plan',
'type' => 'file',
'label' => '上传商业计划书',
'required' => true,
1 month ago
'help' => '包括企业概况与定位、核心产品/服务、市场规模和竞争情况、创新壁垒与差异化优势、核心团队介绍与优势、未来发展战略规划等,PDF格式,建议不超过20页。',
'file_extensions' => ['pdf'],
'file_max_count' => 1,
5 months ago
],
[
'key' => 'supporting',
'type' => 'file',
'label' => '其他佐证材料',
'required' => false,
1 month ago
'help' => '可上传多个文件:企业营业执照扫描件;知识产权相关证明材料(专利证书、商标注册证、软件著作权等),其他佐证材料(产品或服务介绍、获奖证书、投融资证明等)、创始人或主要负责人学历学位等资质证明。单文件 20M 以内,支持:PDF、PPT、PPTX、DOC、DOCX、WPS、RAR、ZIP',
5 months ago
],
1 month ago
]);
}
/**
* @return list<array<string, mixed>>
*/
private function audienceSchemaJson(): array
{
$purposeOptions = SignupOptionCatalog::schemaOptions(SignupOptionCatalog::audiencePurposes());
return $this->withFieldI18n([
[
'key' => 'name',
'type' => 'text',
'label' => '个人姓名',
'required' => true,
'list' => true,
'placeholder' => '请输入姓名',
],
[
'key' => 'phone',
'type' => 'tel',
'label' => '联系电话',
'required' => true,
'list' => true,
'placeholder' => '请输入11位手机号',
],
[
'key' => 'company',
'type' => 'text',
'label' => '所属单位',
'required' => true,
'list' => true,
'placeholder' => '请输入单位名称',
],
[
'key' => 'job',
'type' => 'text',
'label' => '个人职务',
'required' => false,
'list' => true,
'placeholder' => '请输入职务',
],
[
'key' => 'purpose',
'type' => 'select',
'label' => '观赛目的',
'required' => true,
'list' => true,
'filter' => true,
'placeholder' => '请选择观赛目的',
'options' => $purposeOptions,
],
]);
5 months ago
}
/**
* 与前端 src/data/chinaRegion.ts provinceOrder 一致。
*
* @return list<string>
*/
private function provinceOrder(): array
{
return [
'北京市', '天津市', '上海市', '重庆市',
'河北省', '山西省', '内蒙古自治区',
'辽宁省', '吉林省', '黑龙江省',
'江苏省', '浙江省', '安徽省', '福建省', '江西省', '山东省',
'河南省', '湖北省', '湖南省', '广东省', '广西壮族自治区', '海南省',
'四川省', '贵州省', '云南省', '西藏自治区',
'陕西省', '甘肃省', '青海省', '宁夏回族自治区', '新疆维吾尔自治区',
'香港特别行政区', '澳门特别行政区', '台湾省',
];
}
1 month ago
/**
* @param list<array<string, mixed>> $rows
* @return list<array<string, mixed>>
*/
private function withFieldI18n(array $rows): array
{
return SignupFieldI18n::enrichSchemaRows($rows);
}
5 months ago
}