From 6894508d81d5f56601419547bb7e13629943065b Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Thu, 8 Aug 2024 03:14:34 +0800 Subject: [PATCH] exam add max user count --- .../Resources/System/ExamResource.php | 14 +++++- app/Models/Exam.php | 12 ++++- app/Repositories/ExamRepository.php | 19 ++++++++ ...1256_add_max_user_count_to_exams_table.php | 32 +++++++++++++ include/constants.php | 2 +- public/task.php | 45 +++++++------------ resources/lang/en/exam.php | 8 +++- resources/lang/zh_CN/exam.php | 8 +++- resources/lang/zh_TW/exam.php | 8 +++- 9 files changed, 110 insertions(+), 38 deletions(-) create mode 100644 database/migrations/2024_08_08_021256_add_max_user_count_to_exams_table.php 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 = '

'.$title.'

'; stdhead($title); @@ -35,6 +39,7 @@ $columnTargetUserLabel $columnSuccessRewardLabel $columnFailDeductLabel +$columnClaimedUserCountLabel $columnDescriptionDeductLabel $columnClaimLabel @@ -51,10 +56,10 @@ //dd(last_query()); foreach ($rows as $row) { $claimDisabled = $claimClass = ''; - $claimBtnText = "认领"; + $claimBtnText = nexus_trans("exam.action_claim_task"); if ($userTasks->has($row->id)) { $claimDisabled = " disabled"; - $claimBtnText = "已认领"; + $claimBtnText = nexus_trans("exam.claimed_already"); } else { $claimClass = "claim"; } @@ -64,12 +69,13 @@ ); $columns = []; $columns[] = sprintf('%s', $row->name); - $columns[] = sprintf('%s', $row->indexFormatted); + $columns[] = sprintf('%s', $row->indexFormatted); $columns[] = sprintf('%s', $row->getBeginForUser()); $columns[] = sprintf('%s', $row->getEndForUser()); $columns[] = sprintf('%s', $row->filterFormatted); $columns[] = sprintf('%s', number_format($row->success_reward_bonus)); $columns[] = sprintf('%s', number_format($row->fail_deduct_bonus)); + $columns[] = sprintf('%s', sprintf("%s/%s",$row->users_count, $row->max_user_count ?: nexus_trans("label.infinite"))); $columns[] = sprintf('%s', $row->description); $columns[] = sprintf('%s', $claimAction); $table .= sprintf('%s', implode("", $columns)); @@ -83,35 +89,17 @@ jQuery('.claim').on('click', function (e) { let id = jQuery(this).attr('data-id') layer.confirm("{$confirmBuyMsg}", function (index) { + layer.close(index) let params = { action: "claimTask", params: {exam_id: id} } console.log(params) + jQuery('body').loading({ + stoppable: false + }); jQuery.post('ajax.php', params, function(response) { - console.log(response) - if (response.ret != 0) { - layer.alert(response.msg) - return - } - window.location.reload() - }, 'json') - }) -}) -jQuery('.gift').on('click', function (e) { - let medalId = jQuery(this).attr('data-id') - let uid = jQuery(this).prev().val() - if (!uid) { - layer.alert('Require UID') - return - } - layer.confirm("{$confirmGiftMsg}" + uid + " ?", function (index) { - let params = { - action: "giftMedal", - params: {medal_id: medalId, uid: uid} - } - console.log(params) - jQuery.post('ajax.php', params, function(response) { + jQuery('body').loading('stop'); console.log(response) if (response.ret != 0) { layer.alert(response.msg) @@ -122,6 +110,7 @@ }) }) JS; +\Nexus\Nexus::js('vendor/jquery-loading/jquery.loading.min.js', 'footer', true); \Nexus\Nexus::js($js, 'footer', false); stdfoot(); diff --git a/resources/lang/en/exam.php b/resources/lang/en/exam.php index f3523dd6..e4d1895a 100644 --- a/resources/lang/en/exam.php +++ b/resources/lang/en/exam.php @@ -55,8 +55,8 @@ 'type' => 'Type', 'type_help' => 'Exam are regular exam and failing them will result in account banning. Tasks can be set to reward bonus or deduct bonus depending on whether they are completed or not', - 'fail_deduct_bonus' => 'Deduct bonus for task failure', - 'success_reward_bonus' => 'Reward bonus for task completion', + 'fail_deduct_bonus' => 'Deduct bonus for failure', + 'success_reward_bonus' => 'Reward bonus for completion', 'action_claim_task' => 'Claim', 'confirm_to_claim' => 'Sure you want to claim?' , @@ -64,4 +64,8 @@ 'not_match_target_user' => 'You are not a matching target user!' , 'has_other_on_the_way' => 'There is an other :type_text in progress!' , 'claimed_already' => 'Already claimed', + 'not_between_begin_end_time' => 'Not between begin & end time', + 'reach_max_user_count' => 'The number of claimed users has reached its maximum', + 'claimed_user_count' => 'Claimed', + 'max_user_count' => 'Max claim user count(0 means unlimited)', ]; diff --git a/resources/lang/zh_CN/exam.php b/resources/lang/zh_CN/exam.php index 12fe4cbd..f79b3f68 100644 --- a/resources/lang/zh_CN/exam.php +++ b/resources/lang/zh_CN/exam.php @@ -57,8 +57,8 @@ 'type' => '类型', 'type_help' => '考核是常规的考核,不通过会被封禁账号。任务可根据完成与否设置奖励魔力或扣除魔力', - 'fail_deduct_bonus' => '任务失败扣除魔力', - 'success_reward_bonus' => '任务完成奖励魔力', + 'fail_deduct_bonus' => '失败扣除魔力', + 'success_reward_bonus' => '完成奖励魔力', 'action_claim_task' => '领取', 'confirm_to_claim' => '确定要认领吗?', @@ -66,4 +66,8 @@ 'not_match_target_user' => '你不是匹配的目标用户!', 'has_other_on_the_way' => '有其他进行中的:type_text', 'claimed_already' => '已经认领', + 'not_between_begin_end_time' => '不在开始结束时间范围内', + 'reach_max_user_count' => '认领人数已达上限', + 'claimed_user_count' => '认领人数', + 'max_user_count' => '最多认领人数(0表示无限制)', ]; diff --git a/resources/lang/zh_TW/exam.php b/resources/lang/zh_TW/exam.php index c0b465b4..5f439d05 100644 --- a/resources/lang/zh_TW/exam.php +++ b/resources/lang/zh_TW/exam.php @@ -55,8 +55,8 @@ 'type' => '类型', 'type_help' => '考核是常规的考核,不通过会被封禁账号。任务可根据完成与否设置奖励魔力或扣除魔力', - 'fail_deduct_bonus' => '任务失败扣除魔力', - 'success_reward_bonus' => '任务完成奖励魔力', + 'fail_deduct_bonus' => '失败扣除魔力', + 'success_reward_bonus' => '完成奖励魔力', 'action_claim_task' => '領取', 'confirm_to_claim' => '確定要認領嗎?', @@ -64,4 +64,8 @@ 'not_match_target_user' => '你不是匹配的目標用戶!', 'has_other_on_the_way' => '有其他進行中的:type_text', 'claimed_already' => '已經認領', + 'not_between_begin_end_time' => '不在開始結束時間範圍內', + 'reach_max_user_count' => '認領人數已達上限', + 'claimed_user_count' => '認領人數', + 'max_user_count' => '最多認領人數(0表示無限製)', ];