diff --git a/app/Filament/Resources/System/ExamResource.php b/app/Filament/Resources/System/ExamResource.php index 31d551e4..05b29f86 100644 --- a/app/Filament/Resources/System/ExamResource.php +++ b/app/Filament/Resources/System/ExamResource.php @@ -49,22 +49,32 @@ public static function form(Form $form): Form Forms\Components\Section::make(__('label.exam.section_base_info'))->schema([ Forms\Components\TextInput::make('name')->required()->columnSpan(['sm' => 2])->label(__('label.name')), Forms\Components\Select::make('type') - ->required()->columnSpan(['sm' => 2]) + ->required() + ->columnSpanFull() ->label(__('exam.type')) ->options(Exam::listTypeOptions()) ->helperText(__('exam.type_help')) ->reactive() , Forms\Components\TextInput::make('success_reward_bonus') + ->columnSpanFull() ->required() ->label(__('exam.success_reward_bonus')) ->hidden(fn (\Closure $get) => $get('type') != Exam::TYPE_TASK) , Forms\Components\TextInput::make('fail_deduct_bonus') + ->columnSpanFull() ->required() ->label(__('exam.fail_deduct_bonus')) ->hidden(fn (\Closure $get) => $get('type') != Exam::TYPE_TASK) , + Forms\Components\TextInput::make('max_user_count') + ->columnSpanFull() + ->required() + ->numeric() + ->label(__('exam.max_user_count')) + ->hidden(fn (\Closure $get) => $get('type') != Exam::TYPE_TASK) + , Forms\Components\Repeater::make('indexes')->schema([ Forms\Components\Select::make('index') @@ -148,7 +158,7 @@ public static function table(Table $table): Table Tables\Columns\TextColumn::make('end')->label(__('label.end')), Tables\Columns\TextColumn::make('durationText')->label(__('label.duration')), Tables\Columns\TextColumn::make('recurringText')->label(__('exam.recurring')), - Tables\Columns\TextColumn::make('filterFormatted')->label(__('label.exam.filter_formatted'))->html(), + Tables\Columns\TextColumn::make('filterFormatted')->label(__('label.exam.filter_formatted'))->html()->extraAttributes([]), Tables\Columns\BooleanColumn::make('is_discovered')->label(__('label.exam.is_discovered')), Tables\Columns\TextColumn::make('priority')->label(__('label.priority')), Tables\Columns\TextColumn::make('statusText')->label(__('label.status')), diff --git a/app/Models/Exam.php b/app/Models/Exam.php index 8f7c0d3f..71d5de65 100644 --- a/app/Models/Exam.php +++ b/app/Models/Exam.php @@ -11,7 +11,7 @@ class Exam extends NexusModel { protected $fillable = [ 'name', 'description', 'begin', 'end', 'duration', 'status', 'is_discovered', 'filters', 'indexes', 'priority', - 'recurring', 'type', 'success_reward_bonus', 'fail_deduct_bonus' + 'recurring', 'type', 'success_reward_bonus', 'fail_deduct_bonus', 'max_user_count' ]; public $timestamps = true; @@ -294,4 +294,14 @@ public function isTypeTask(): bool return $this->type == self::TYPE_TASK; } + public function users() + { + return $this->belongsToMany(User::class, "exam_users", "exam_id", "uid"); + } + + public function OnGoingUsers() + { + return $this->users()->wherePivot("status", ExamUser::STATUS_NORMAL); + } + } diff --git a/app/Repositories/ExamRepository.php b/app/Repositories/ExamRepository.php index f5544da5..ebcaea9c 100644 --- a/app/Repositories/ExamRepository.php +++ b/app/Repositories/ExamRepository.php @@ -368,6 +368,19 @@ public function assignToUser(int $uid, int $examId, $begin = null, $end = null) $locale = $user->locale; $authUserClass = get_user_class(); $authUserId = get_user_id(); + $now = Carbon::now(); + if (!empty($exam->begin)) { + $specificBegin = Carbon::parse($exam->begin); + if ($specificBegin->isAfter($now)) { + throw new NexusException(nexus_trans("exam.not_between_begin_end_time", [], $locale)); + } + } + if (!empty($exam->end)) { + $specificEnd = Carbon::parse($exam->end); + if ($specificEnd->isBefore($now)) { + throw new NexusException(nexus_trans("exam.not_between_begin_end_time", [], $locale)); + } + } if ($exam->isTypeExam()) { if ($authUserClass <= $user->class) { //exam only can assign by upper class admin @@ -378,6 +391,12 @@ public function assignToUser(int $uid, int $examId, $begin = null, $end = null) //task only can be claimed by self throw new NexusException(nexus_trans('exam.claim_by_yourself_only', [], $locale)); } + if ($exam->max_user_count > 0) { + $claimUserCount = ExamUser::query()->where("exam_id", $examId)->count(); + if ($claimUserCount >= $exam->max_user_count) { + throw new NexusException(nexus_trans('exam.reach_max_user_count', [], $locale)); + } + } } if (!$this->isExamMatchUser($exam, $user)) { diff --git a/database/migrations/2024_08_08_021256_add_max_user_count_to_exams_table.php b/database/migrations/2024_08_08_021256_add_max_user_count_to_exams_table.php new file mode 100644 index 00000000..09e9a3bd --- /dev/null +++ b/database/migrations/2024_08_08_021256_add_max_user_count_to_exams_table.php @@ -0,0 +1,32 @@ +integer("max_user_count")->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('exams', function (Blueprint $table) { + $table->dropColumn("max_user_count"); + }); + } +}; diff --git a/include/constants.php b/include/constants.php index 0b1d7c2a..ad8d7788 100644 --- a/include/constants.php +++ b/include/constants.php @@ -1,6 +1,6 @@ where('type', \App\Models\Exam::TYPE_TASK)->where("status", \App\Models\Exam::STATUS_ENABLED); +$query = \App\Models\Exam::query() + ->where('type', \App\Models\Exam::TYPE_TASK) + ->where("status", \App\Models\Exam::STATUS_ENABLED) +; $total = (clone $query)->count(); $perPage = 20; list($paginationTop, $paginationBottom, $limit, $offset) = pager($perPage, $total, "?"); -$rows = (clone $query)->offset($offset)->take($perPage)->orderBy('id', 'desc')->get(); +$rows = (clone $query)->offset($offset)->take($perPage)->orderBy('id', 'desc')->withCount("users")->get(); $title = nexus_trans('exam.type_task'); $columnNameLabel = nexus_trans('label.name'); $columnIndexLabel = nexus_trans('exam.index'); @@ -20,6 +23,7 @@ $columnFailDeductLabel = nexus_trans('exam.fail_deduct_bonus'); $columnDescriptionDeductLabel = nexus_trans('label.description'); $columnClaimLabel = nexus_trans('exam.action_claim_task'); +$columnClaimedUserCountLabel = nexus_trans('exam.claimed_user_count'); $header = '