diff --git a/app/Models/BonusLogs.php b/app/Models/BonusLogs.php index 22b69f6d..63c15887 100644 --- a/app/Models/BonusLogs.php +++ b/app/Models/BonusLogs.php @@ -36,6 +36,8 @@ class BonusLogs extends NexusModel const BUSINESS_TYPE_BUY_CHANGE_USERNAME_CARD = 17; const BUSINESS_TYPE_GIFT_MEDAL = 18; const BUSINESS_TYPE_BUY_TORRENT = 19; + const BUSINESS_TYPE_TASK_NOT_PASS_DEDUCT = 20; + const BUSINESS_TYPE_TASK_PASS_REWARD = 21; const BUSINESS_TYPE_ROLE_WORK_SALARY = 1000; const BUSINESS_TYPE_TORRENT_BE_DOWNLOADED = 1001; diff --git a/app/Models/Exam.php b/app/Models/Exam.php index e5dd3147..0333467a 100644 --- a/app/Models/Exam.php +++ b/app/Models/Exam.php @@ -254,4 +254,32 @@ class Exam extends NexusModel throw new \RuntimeException("Invalid recurring: $recurring"); } + public function getMessageSubjectTransKey(string $result): string + { + return match ($this->type) { + self::TYPE_EXAM => "exam.checkout_{$result}_message_subject_for_exam", + self::TYPE_TASK => "exam.checkout_{$result}_message_subject_for_task", + default => throw new \RuntimeException("Invalid type: " . $this->type) + }; + } + + public function getMessageContentTransKey(string $result): string + { + return match ($this->type) { + self::TYPE_EXAM => "exam.checkout_{$result}_message_content_for_exam", + self::TYPE_TASK => "exam.checkout_{$result}_message_content_for_task", + default => throw new \RuntimeException("Invalid type: " . $this->type) + }; + } + + public function isTypeExam(): bool + { + return $this->type == self::TYPE_EXAM; + } + + public function isTypeTask(): bool + { + return $this->type == self::TYPE_TASK; + } + } diff --git a/app/Models/User.php b/app/Models/User.php index 55a480e1..eccddb2a 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -514,6 +514,11 @@ class User extends Authenticatable implements FilamentUser, HasName return $this->hasMany(UserPermission::class, 'uid'); } + public function examAndTasks(): \Illuminate\Database\Eloquent\Relations\BelongsToMany + { + return $this->belongsToMany(Exam::class, "exam_users", "uid", "exam_id"); + } + public function getAvatarAttribute($value) { if ($value) { diff --git a/app/Repositories/ExamRepository.php b/app/Repositories/ExamRepository.php index 61b9bcf7..27f342f3 100644 --- a/app/Repositories/ExamRepository.php +++ b/app/Repositories/ExamRepository.php @@ -2,6 +2,7 @@ namespace App\Repositories; use App\Exceptions\NexusException; +use App\Models\BonusLogs; use App\Models\Exam; use App\Models\ExamProgress; use App\Models\ExamUser; @@ -1100,11 +1101,13 @@ class ExamRepository extends BaseRepository $result += $examUsers->count(); $now = Carbon::now()->toDateTimeString(); $examUserIdArr = $uidToDisable = $messageToSend = $userBanLog = $userModcommentUpdate = []; + $bonusLog = $userBonusCommentUpdate = $userBonusUpdate = $uidToUpdateBonus = []; $examUserToInsert = []; foreach ($examUsers as $examUser) { $minId = $examUser->id; $examUserIdArr[] = $examUser->id; $uid = $examUser->uid; + clear_inbox_count_cache($uid); /** @var Exam $exam */ $exam = $examUser->exam; $currentLogPrefix = sprintf("$logPrefix, user: %s, exam: %s, examUser: %s", $uid, $examUser->exam_id, $examUser->id); @@ -1119,48 +1122,95 @@ class ExamRepository extends BaseRepository $locale = $examUser->user->locale; if ($examUser->is_done) { do_log("$currentLogPrefix, [is_done]"); - $subjectTransKey = 'exam.checkout_pass_message_subject'; - $msgTransKey = 'exam.checkout_pass_message_content'; - if (!empty($exam->recurring) && $this->isExamMatchUser($exam, $examUser->user)) { - $examUserToInsert[] = [ - 'uid' => $examUser->user->id, - 'exam_id' => $exam->id, - 'begin' => $exam->getBeginForUser(), - 'end' => $exam->getEndForUser(), - 'created_at' => $now, - 'updated_at' => $now, - ]; + $subjectTransKey = $exam->getMessageSubjectTransKey("pass"); + $msgTransKey = $exam->getMessageContentTransKey("pass"); + if ($exam->isTypeExam()) { + if (!empty($exam->recurring) && $this->isExamMatchUser($exam, $examUser->user)) { + $examUserToInsert[] = [ + 'uid' => $examUser->user->id, + 'exam_id' => $exam->id, + 'begin' => $exam->getBeginForUser(), + 'end' => $exam->getEndForUser(), + 'created_at' => $now, + 'updated_at' => $now, + ]; + } + } elseif ($exam->isTypeTask()) { + //reward bonus + if ($exam->success_reward_bonus > 0) { + $uidToUpdateBonus[] = $uid; + $bonusLog[] = [ + "uid" => $uid, + "old_total_value" => $examUser->user->seedbonus, + "value" => $exam->success_reward_bonus, + "new_total_value" => $examUser->user->seedbonus + $exam->success_reward_bonus, + "business_type" => BonusLogs::BUSINESS_TYPE_TASK_PASS_REWARD, + ]; + $userBonusComment = nexus_trans("exam.reward_bonus_comment", [ + 'exam_name' => $exam->name, + 'begin' => $examUser->begin, + 'end' => $examUser->end, + 'success_reward_bonus' => $exam->success_reward_bonus, + ], $locale); + $userBonusCommentUpdate[] = sprintf("when `id` = %s then concat_ws('\n', '%s', bonuscomment)", $uid, $userBonusComment); + $userBonusUpdate[] = sprintf("when `id` = %s then seedbonus + %d", $uid, $exam->success_reward_bonus); + } } } else { - do_log("$currentLogPrefix, [will be banned]"); - clear_user_cache($examUser->user->id, $examUser->user->passkey); - $subjectTransKey = 'exam.checkout_not_pass_message_subject'; - $msgTransKey = 'exam.checkout_not_pass_message_content'; - //ban user - $uidToDisable[] = $uid; - $userModcomment = nexus_trans('exam.ban_user_modcomment', [ - 'exam_name' => $exam->name, - 'begin' => $examUser->begin, - 'end' => $examUser->end - ], $locale); - $userModcomment = sprintf('%s - %s', date('Y-m-d'), $userModcomment); - $userModcommentUpdate[] = sprintf("when `id` = %s then concat_ws('\n', '%s', modcomment)", $uid, $userModcomment); - $banLogReason = nexus_trans('exam.ban_log_reason', [ - 'exam_name' => $exam->name, - 'begin' => $examUser->begin, - 'end' => $examUser->end, - ], $locale); - $userBanLog[] = [ - 'uid' => $uid, - 'username' => $examUser->user->username, - 'reason' => $banLogReason, - ]; + do_log("$currentLogPrefix, [not_done]"); + $subjectTransKey = $exam->getMessageSubjectTransKey("not_pass"); + $msgTransKey = $exam->getMessageContentTransKey("not_pass"); + if ($exam->isTypeExam()) { + //ban user + do_log("$currentLogPrefix, [will be banned]"); + clear_user_cache($examUser->user->id, $examUser->user->passkey); + $uidToDisable[] = $uid; + $userModcomment = nexus_trans('exam.ban_user_modcomment', [ + 'exam_name' => $exam->name, + 'begin' => $examUser->begin, + 'end' => $examUser->end + ], $locale); + $userModcomment = sprintf('%s - %s', date('Y-m-d'), $userModcomment); + $userModcommentUpdate[] = sprintf("when `id` = %s then concat_ws('\n', '%s', modcomment)", $uid, $userModcomment); + $banLogReason = nexus_trans('exam.ban_log_reason', [ + 'exam_name' => $exam->name, + 'begin' => $examUser->begin, + 'end' => $examUser->end, + ], $locale); + $userBanLog[] = [ + 'uid' => $uid, + 'username' => $examUser->user->username, + 'reason' => $banLogReason, + ]; + } elseif ($exam->isTypeTask()) { + //deduct bonus + if ($exam->fail_deduct_bonus > 0) { + $uidToUpdateBonus[] = $uid; + $bonusLog[] = [ + "uid" => $uid, + "old_total_value" => $examUser->user->seedbonus, + "value" => -1*$exam->fail_deduct_bonus, + "new_total_value" => $examUser->user->seedbonus - $exam->fail_deduct_bonus, + "business_type" => BonusLogs::BUSINESS_TYPE_TASK_NOT_PASS_DEDUCT, + ]; + $userBonusComment = nexus_trans("exam.deduct_bonus_comment", [ + 'exam_name' => $exam->name, + 'begin' => $examUser->begin, + 'end' => $examUser->end, + 'fail_deduct_bonus' => $exam->fail_deduct_bonus, + ], $locale); + $userBonusCommentUpdate[] = sprintf("when `id` = %s then concat_ws('\n', '%s', bonuscomment)", $uid, $userBonusComment); + $userBonusUpdate[] = sprintf("when `id` = %s then seedbonus - %d", $uid, $exam->fail_deduct_bonus); + } + } } $subject = nexus_trans($subjectTransKey, [], $locale); $msg = nexus_trans($msgTransKey, [ 'exam_name' => $exam->name, 'begin' => $examUser->begin, - 'end' => $examUser->end + 'end' => $examUser->end, + 'success_reward_bonus' => $exam->success_reward_bonus, + 'fail_deduct_bonus' => $exam->fail_deduct_bonus, ], $locale); $messageToSend[] = [ 'receiver' => $uid, @@ -1169,7 +1219,7 @@ class ExamRepository extends BaseRepository 'msg' => $msg ]; } - DB::transaction(function () use ($uidToDisable, $messageToSend, $examUserIdArr, $examUserToInsert, $userBanLog, $userModcommentUpdate, $userTable, $logPrefix) { + DB::transaction(function () use ($uidToDisable, $messageToSend, $examUserIdArr, $examUserToInsert, $userBanLog, $userModcommentUpdate, $userBonusUpdate, $userBonusCommentUpdate, $bonusLog, $uidToUpdateBonus, $userTable, $logPrefix) { ExamUser::query()->whereIn('id', $examUserIdArr)->update(['status' => ExamUser::STATUS_FINISHED]); do { $deleted = ExamProgress::query()->whereIn('exam_user_id', $examUserIdArr)->limit(10000)->delete(); @@ -1191,6 +1241,18 @@ class ExamRepository extends BaseRepository if (!empty($examUserToInsert)) { ExamUser::query()->insert($examUserToInsert); } + if (!empty($userBonusUpdate)) { + $uidStr = implode(', ', $uidToUpdateBonus); + $sql = sprintf( + "update %s set seedbonus = case %s, bonuscomment = case %s end where id in (%s)", + $userTable, implode(' ', $userBonusUpdate), implode(",", $userBonusCommentUpdate), $uidStr + ); + $updateResult = DB::update($sql); + do_log(sprintf("$logPrefix, update %s users: %s seedbonus, sql: %s, updateResult: %s", count($uidToUpdateBonus), $uidStr, $sql, $updateResult)); + } + if (!empty($bonusLog)) { + BonusLogs::query()->insert($bonusLog); + } }); } return $result; diff --git a/include/functions.php b/include/functions.php index 98f16b11..54241436 100644 --- a/include/functions.php +++ b/include/functions.php @@ -2670,6 +2670,7 @@ else { []: '.$lang_functions['text_attended'].'', $attendance->points, $CURUSER['attendance_card']); }else{ printf(' %s', $lang_functions['text_attendance']);}?> [] + [] []: where('inviter', $CURUSER['id'])->where('invitee', '')->where('expired_at', '>', now())->count())?> = \App\Models\User::getAccessAdminClassMin()) printf('[%s]', nexus_env('FILAMENT_PATH', 'nexusphp'), $lang_functions['text_management_system'])?>
diff --git a/public/task.php b/public/task.php new file mode 100644 index 00000000..319197f1 --- /dev/null +++ b/public/task.php @@ -0,0 +1,125 @@ +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(); +$title = nexus_trans('exam.type_task'); +$columnNameLabel = nexus_trans('label.name'); +$columnIndexLabel = nexus_trans('exam.index'); +$columnBeginTimeLabel = nexus_trans('label.begin'); +$columnEndTimeLabel = nexus_trans('label.end'); +$columnDurationLabel = nexus_trans('label.duration'); +$columnRecurringLabel = nexus_trans('exam.recurring'); +$columnTargetUserLabel = nexus_trans('label.exam.filter_formatted'); +$columnDescLabel = nexus_trans('label.description'); +$columnSuccessRewardLabel = nexus_trans('exam.success_reward_bonus'); +$columnFailDeductLabel = nexus_trans('exam.fail_deduct_bonus'); +$columnDescriptionDeductLabel = nexus_trans('label.description'); +$columnClaimLabel = nexus_trans('exam.action_claim_task'); + +$header = '

'.$title.'

'; +stdhead($title); +begin_main_frame(); +$table = << + + + + + + + + + + + + + +TABLE; +$now = now(); +$table .= ''; +$userInfo = \App\Models\User::query()->findOrFail($CURUSER['id'], \App\Models\User::$commonFields); +$userTasks = $userInfo->examAndTasks()->where("type", \App\Models\Exam::TYPE_TASK) + ->orderBy('id', 'desc') + ->get() + ->keyBy('id') +; +//dd($userTasks); +foreach ($rows as $row) { + $claimDisabled = $claimClass = ''; + $claimBtnText = "认领"; + if ($userTasks->has($row->id)) { + $claimDisabled = " disabled"; + $claimBtnText = "已认领"; + } + $claimAction = sprintf( + '', + $claimClass, $row->id, $claimBtnText, $claimDisabled + ); + $columns = []; + $columns[] = sprintf('', $row->name); + $columns[] = sprintf('', $row->indexFormatted); + $columns[] = sprintf('', $row->getBeginForUser()); + $columns[] = sprintf('', $row->getEndForUser()); + $columns[] = sprintf('', $row->filterFormatted); + $columns[] = sprintf('', number_format($row->success_reward_bonus)); + $columns[] = sprintf('', number_format($row->fail_deduct_bonus)); + $columns[] = sprintf('', $row->description); + $columns[] = sprintf('', $claimAction); + $table .= sprintf('%s', implode("", $columns)); +} +$table .= '
$columnNameLabel$columnIndexLabel$columnBeginTimeLabel$columnEndTimeLabel$columnTargetUserLabel$columnSuccessRewardLabel$columnFailDeductLabel$columnDescriptionDeductLabel$columnClaimLabel
%s%s%s%s%s%s%s%s%s
'; +echo $header . $table . $paginationBottom; +end_main_frame(); +$confirmBuyMsg = nexus_trans('medal.confirm_to_buy'); +$confirmGiftMsg = nexus_trans('medal.confirm_to_gift'); +$js = << '购买改名卡', \App\Models\BonusLogs::BUSINESS_TYPE_GIFT_MEDAL => '赠送勋章', \App\Models\BonusLogs::BUSINESS_TYPE_BUY_TORRENT => '购买种子', + \App\Models\BonusLogs::BUSINESS_TYPE_TASK_PASS_REWARD => '任务完成奖励', + \App\Models\BonusLogs::BUSINESS_TYPE_TASK_NOT_PASS_DEDUCT => '任务未完成扣除', \App\Models\BonusLogs::BUSINESS_TYPE_ROLE_WORK_SALARY => '工作组工资', \App\Models\BonusLogs::BUSINESS_TYPE_TORRENT_BE_DOWNLOADED => '种子被下载', diff --git a/resources/lang/zh_CN/exam.php b/resources/lang/zh_CN/exam.php index 07bf8098..488b3f54 100644 --- a/resources/lang/zh_CN/exam.php +++ b/resources/lang/zh_CN/exam.php @@ -2,9 +2,9 @@ return [ 'label' => '考核', - 'name' => '考核名称', - 'index' => '考核指标', - 'time_range' => '考核时间', + 'name' => '名称', + 'index' => '指标', + 'time_range' => '时间', 'index_text_' . \App\Models\Exam::INDEX_UPLOADED => '上传增量', 'index_text_' . \App\Models\Exam::INDEX_SEED_TIME_AVERAGE => '平均做种时间', 'index_text_' . \App\Models\Exam::INDEX_DOWNLOADED => '下载增量', @@ -20,14 +20,25 @@ return [ 'require_value' => '要求', 'current_value' => '当前', 'result' => '结果', - 'result_pass' => '通过!', - 'result_not_pass' => '未通过!', - 'checkout_pass_message_subject' => '考核通过!', - 'checkout_pass_message_content' => '恭喜!你在规定时间内(:begin ~ :end)顺利完成了考核::exam_name。', - 'checkout_not_pass_message_subject' => '考核未通过,账号被禁用!', - 'checkout_not_pass_message_content' => '你在规定时间内(:begin ~ :end)未完成考核::exam_name,账号已被禁用。', + 'result_pass_for_exam' => '通过!', + 'result_pass_for_task' => '完成!', + 'result_not_pass_for_exam' => '未通过!', + 'result_not_pass_for_task' => '未完成!', + 'checkout_pass_message_subject_for_exam' => '考核通过!', + 'checkout_pass_message_content_for_exam' => '恭喜!你在规定时间内(:begin ~ :end)顺利完成了考核::exam_name。', + 'checkout_not_pass_message_subject_for_exam' => '考核未通过,账号被禁用!', + 'checkout_not_pass_message_content_for_exam' => '你在规定时间内(:begin ~ :end)未完成考核::exam_name,账号已被禁用。', + + 'checkout_pass_message_subject_for_task' => '任务完成!', + 'checkout_pass_message_content_for_task' => '恭喜!你在规定时间内(:begin ~ :end)顺利完成了任务::exam_name,获得奖励魔力::success_reward_bonus', + 'checkout_not_pass_message_subject_for_task' => '任务未完成!', + 'checkout_not_pass_message_content_for_task' => '你在规定时间内(:begin ~ :end)未完成任务::exam_name,扣除魔力::fail_deduct_bonus。', + 'ban_log_reason' => '未完成考核::exam_name(:begin ~ :end)', 'ban_user_modcomment' => '未完成考核: :exam_name(:begin ~ :end), 被系统禁用.', + 'deduct_bonus_comment' => '未完成任务: :exam_name(:begin ~ :end), 扣除魔力::fail_deduct_bonus.', + 'reward_bonus_comment' => '完成任务: :exam_name(:begin ~ :end), 奖励魔力::success_reward_bonus.', + 'admin' => [ 'list' => [ 'page_title' => '考核列表' @@ -49,4 +60,6 @@ return [ 'fail_deduct_bonus' => '任务失败扣除魔力', 'success_reward_bonus' => '任务完成奖励魔力', + 'action_claim_task' => '领取', + ];