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.

159 lines
4.5 KiB

5 months ago
<?php
namespace App\Models;
3 months ago
use App\Support\ProjectCode;
5 months ago
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
3 months ago
use Illuminate\Support\Facades\Schema;
5 months ago
use Illuminate\Validation\ValidationException;
class Application extends Model
{
protected $fillable = [
3 months ago
'project_code',
5 months ago
'user_id',
'competition_id',
'signup_channel_id',
'signup_channel_code',
'signup_channel_state',
'signup_channel_entered_at',
3 months ago
'recommend',
5 months ago
'status',
'player_name',
'school',
'degree',
'contact_email',
'contact_mobile',
5 months ago
'entry_group',
5 months ago
'company_name',
'project_name',
'track',
'location_country',
'location_province',
'location_city',
'oversea_country',
'intro',
'promise_signed_at',
'promise_signature',
'submitted_at',
];
protected $casts = [
'promise_signed_at' => 'datetime',
'submitted_at' => 'datetime',
'signup_channel_entered_at' => 'datetime',
5 months ago
];
3 months ago
protected static function booted(): void
{
static::created(function (Application $application): void {
3 months ago
if (! Schema::hasColumn($application->getTable(), 'project_code')) {
return;
}
3 months ago
if (trim((string) ($application->project_code ?? '')) === '') {
$application->forceFill([
'project_code' => ProjectCode::forApplication($application),
])->saveQuietly();
}
});
}
3 months ago
public static function firstOrCreateDraft(int $userId, int $competitionId): self
{
return static::query()->firstOrCreate(
[
'user_id' => $userId,
'competition_id' => $competitionId,
],
['status' => 'draft']
);
}
5 months ago
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function competition(): BelongsTo
{
return $this->belongsTo(Competition::class);
}
public function signupChannel(): BelongsTo
{
return $this->belongsTo(SignupChannel::class);
}
5 months ago
public function files(): HasMany
{
return $this->hasMany(ApplicationFile::class);
}
public function reviewRecords(): HasMany
{
return $this->hasMany(ApplicationReviewRecord::class);
}
public function reviewScores(): HasMany
{
return $this->hasMany(ApplicationReviewScore::class);
}
public function isSubmitted(): bool
{
return $this->status === 'submitted';
}
/** 评委已产生评审记录或打分后,选手端不可再修改报名/附件 */
public function isSignupLockedByReview(): bool
{
return $this->reviewRecords()->exists() || $this->reviewScores()->exists();
}
/** 已超过赛事设置的报名截止时间(未设置截止时间则不据此拦截) */
public function isPastSignupCloseForCompetition(): bool
{
$this->loadMissing('competition');
$close = $this->competition?->signup_close_at;
return $close !== null && now()->isAfter($close);
}
/**
* 选手是否仍可编辑报名表:报名截止时间内且评委尚未评审;草稿与已提交均可继续改报直至截止或评审落库。
*/
public function participantMayEditSignup(): bool
{
if ($this->isSignupLockedByReview()) {
return false;
}
return ! $this->isPastSignupCloseForCompetition();
}
/**
5 months ago
* @param 'status'|'file' $field 422 时 errors 字段名(报名表用 status,附件接口用 file)
5 months ago
*/
public function assertMayEditSignup(string $field = 'status'): void
{
if ($this->isSignupLockedByReview()) {
$msg = $field === 'file'
? '已有评委评审或打分记录,不可再上传或删除附件'
: '已有评委评审或打分记录,报名内容不可再修改';
throw ValidationException::withMessages([$field => [$msg]]);
}
if ($this->isPastSignupCloseForCompetition()) {
$msg = $field === 'file'
? '报名已截止,不可再上传或删除附件'
: '报名已截止,无法再修改或提交报名';
throw ValidationException::withMessages([$field => [$msg]]);
}
}
}