| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718 |
- <?php
- namespace App\Module\Game\Logics;
- use App\Module\Game\Dtos\RewardGroupDto;
- use App\Module\Game\Dtos\RewardItemDto;
- use App\Module\Game\Dtos\RewardResultDto;
- use App\Module\Game\Enums\REWARD_TYPE;
- use App\Module\Game\Enums\REWARD_MODE;
- use App\Module\Game\Events\RewardGrantedEvent;
- use App\Module\Game\Models\GameRewardGroup;
- use App\Module\Game\Models\GameRewardItem;
- use App\Module\Game\Models\GameRewardLog;
- use App\Module\GameItems\Services\ItemService;
- use Exception;
- use Illuminate\Support\Facades\Log;
- use ReflectionClass;
- use UCore\Db\Helper;
- /**
- * 奖励处理逻辑类
- *
- * 负责处理奖励的发放、记录等内部逻辑
- */
- class RewardLogic
- {
- /**
- * 获取奖励组
- *
- * @param int|string $groupIdOrCode 奖励组ID或编码
- * @return RewardGroupDto|null
- */
- public function getRewardGroup($groupIdOrCode): ?RewardGroupDto
- {
- $query = GameRewardGroup::with('rewardItems');
- if (is_numeric($groupIdOrCode)) {
- $group = $query->find($groupIdOrCode);
- } else {
- $group = $query->where('code', $groupIdOrCode)->first();
- }
- if (!$group) {
- return null;
- }
- return RewardGroupDto::fromModel($group, true);
- }
- /**
- * 发放奖励
- *
- * @param int $userId 用户ID
- * @param int|string $groupIdOrCode 奖励组ID或编码
- * @param string $sourceType 来源类型
- * @param int $sourceId 来源ID
- * @return RewardResultDto 奖励结果
- */
- public function grantReward(int $userId, $groupIdOrCode, string $sourceType, int $sourceId): RewardResultDto
- {
- try {
- // 获取奖励组
- $groupDto = $this->getRewardGroup($groupIdOrCode);
- if (!$groupDto) {
- return RewardResultDto::fail("奖励组不存在: {$groupIdOrCode}");
- }
- // 确定要发放的奖励项
- $rewardItems = $this->determineRewardItems($groupDto);
- if (empty($rewardItems)) {
- return RewardResultDto::fail("奖励组中没有可发放的奖励项");
- }
- // 检查事务是否已开启
- Helper::check_tr();
- // 发放各类奖励
- foreach ($rewardItems as $item) {
- $this->processRewardItem($userId, $item, $sourceType, $sourceId);
- }
- // 记录奖励日志
- $this->logReward($userId, $groupDto->id, $sourceType, $sourceId, $rewardItems);
- // 触发奖励发放事件
- event(new RewardGrantedEvent($userId, $groupDto->id, $groupDto->code, $sourceType, $sourceId, $rewardItems));
- // 返回成功结果
- return RewardResultDto::success(
- $userId,
- $groupDto->id,
- $groupDto->code,
- $groupDto->name,
- $sourceType,
- $sourceId,
- $rewardItems
- );
- } catch (Exception $e) {
- Log::error("发放奖励失败", [
- 'userId' => $userId,
- 'groupIdOrCode' => $groupIdOrCode,
- 'sourceType' => $sourceType,
- 'sourceId' => $sourceId,
- 'error' => $e->getMessage(),
- 'trace' => $e->getTraceAsString()
- ]);
- return RewardResultDto::fail("发放奖励失败: " . $e->getMessage());
- }
- }
- /**
- * 确定要发放的奖励项
- *
- * @param RewardGroupDto $groupDto 奖励组DTO
- * @return RewardItemDto[] 要发放的奖励项
- */
- private function determineRewardItems(RewardGroupDto $groupDto): array
- {
- $items = $groupDto->items;
- // 检查奖励模式
- $rewardMode = $groupDto->rewardMode ?? REWARD_MODE::WEIGHT_SELECTION->value;
- if ($rewardMode == REWARD_MODE::INDEPENDENT_PROBABILITY->value) {
- // 独立概率模式:每个奖励项独立判断是否获得
- return $this->determineRewardItemsByProbability($items);
- } else {
- // 权重选择模式:传统的权重选择机制
- return $this->determineRewardItemsByWeight($groupDto);
- }
- }
- /**
- * 独立概率模式:每个奖励项独立判断是否获得
- *
- * @param RewardItemDto[] $items 奖励项列表
- * @return RewardItemDto[] 要发放的奖励项
- */
- private function determineRewardItemsByProbability(array $items): array
- {
- $selectedItems = [];
- foreach ($items as $item) {
- // 必中项直接添加
- if ($item->isGuaranteed) {
- $selectedItems[] = $this->processRewardItemQuantity($item);
- continue;
- }
- // 检查是否有概率设置
- $probability = $item->probability ?? 0;
- if ($probability <= 0) {
- continue; // 概率为0或未设置,跳过
- }
- // 生成随机数判断是否命中
- $random = mt_rand(1, 10000) / 100; // 生成0.01-100.00的随机数
- if ($random <= $probability) {
- $selectedItems[] = $this->processRewardItemQuantity($item);
- }
- // 未命中则不添加到结果中(实现"未命中没有"的需求)
- }
- return $selectedItems;
- }
- /**
- * 权重选择模式:传统的权重选择机制
- *
- * @param RewardGroupDto $groupDto 奖励组DTO
- * @return RewardItemDto[] 要发放的奖励项
- */
- private function determineRewardItemsByWeight(RewardGroupDto $groupDto): array
- {
- $items = $groupDto->items;
- // 如果不是随机发放,返回所有奖励项
- if (!$groupDto->isRandom) {
- return array_map([$this, 'processRewardItemQuantity'], $items);
- }
- // 如果是随机发放,按权重随机选择指定数量的奖励项
- $selectedItems = [];
- $guaranteedItems = [];
- $normalItems = [];
- // 先分离必中项和普通项
- foreach ($items as $item) {
- if ($item->isGuaranteed) {
- $guaranteedItems[] = $item;
- } else {
- $normalItems[] = $item;
- }
- }
- // 先选择必中项
- $selectedItems = array_map([$this, 'processRewardItemQuantity'], $guaranteedItems);
- // 如果必中项数量已经达到或超过随机数量,直接返回必中项
- if (count($selectedItems) >= $groupDto->randomCount) {
- return array_slice($selectedItems, 0, $groupDto->randomCount);
- }
- // 计算剩余需要选择的数量
- $remainingCount = $groupDto->randomCount - count($selectedItems);
- // 如果没有普通项,直接返回必中项
- if (empty($normalItems)) {
- return $selectedItems;
- }
- // 按权重随机选择普通项
- $totalWeight = array_sum(array_map(function ($item) {
- return $item->weight;
- }, $normalItems));
- // 如果总权重为0,随机选择
- if ($totalWeight <= 0) {
- shuffle($normalItems);
- $selectedNormalItems = array_slice($normalItems, 0, $remainingCount);
- } else {
- // 按权重随机选择
- $selectedNormalItems = [];
- for ($i = 0; $i < $remainingCount; $i++) {
- if (empty($normalItems)) {
- break;
- }
- $randomWeight = mt_rand(1, $totalWeight * 100) / 100;
- $currentWeight = 0;
- foreach ($normalItems as $key => $item) {
- $currentWeight += $item->weight;
- if ($randomWeight <= $currentWeight) {
- $selectedNormalItems[] = $this->processRewardItemQuantity($item);
- $totalWeight -= $item->weight;
- unset($normalItems[$key]);
- $normalItems = array_values($normalItems);
- break;
- }
- }
- }
- }
- // 合并必中项和选中的普通项
- return array_merge($selectedItems, $selectedNormalItems);
- }
- /**
- * 处理奖励项的数量(支持数量范围)
- *
- * @param RewardItemDto $item 奖励项
- * @return RewardItemDto 处理后的奖励项
- */
- private function processRewardItemQuantity(RewardItemDto $item): RewardItemDto
- {
- // 克隆奖励项以避免修改原始数据
- $processedItem = clone $item;
- // 检查是否有数量范围设置
- if ($item->minQuantity !== null && $item->maxQuantity !== null) {
- // 使用数量范围
- $minQty = max(1, $item->minQuantity);
- $maxQty = max($minQty, $item->maxQuantity);
- $processedItem->quantity = mt_rand($minQty, $maxQty);
- } else {
- // 使用固定数量
- $processedItem->quantity = max(1, $item->quantity);
- }
- return $processedItem;
- }
- /**
- * 处理单个奖励项
- *
- * @param int $userId 用户ID
- * @param RewardItemDto $item 奖励项
- * @param string $sourceType 来源类型
- * @param int $sourceId 来源ID
- * @return void
- * @throws Exception
- */
- private function processRewardItem(int $userId, RewardItemDto $item, string $sourceType, int $sourceId): void
- {
- switch ($item->rewardType) {
- case REWARD_TYPE::ITEM->valueInt():
- $this->processItemReward($userId, $item, $sourceType, $sourceId);
- break;
- case REWARD_TYPE::FUND_CONFIG->valueInt():
- $this->processFundConfigReward($userId, $item, $sourceType, $sourceId);
- break;
- case REWARD_TYPE::CURRENCY->valueInt():
- $this->processCurrencyReward($userId, $item, $sourceType, $sourceId);
- break;
- case REWARD_TYPE::PET_EXP->valueInt():
- $this->processPetExpReward($userId, $item, $sourceType, $sourceId);
- break;
- case REWARD_TYPE::PET_ENERGY->valueInt():
- $this->processPetEnergyReward($userId, $item, $sourceType, $sourceId);
- break;
- case REWARD_TYPE::FARM_SHRINE->valueInt():
- $this->processFarmShrineReward($userId, $item, $sourceType, $sourceId);
- break;
- case REWARD_TYPE::OTHER->valueInt():
- $this->processOtherReward($userId, $item, $sourceType, $sourceId);
- break;
- default:
- // 未知奖励类型,记录日志
- Log::warning("未知的奖励类型", [
- 'userId' => $userId,
- 'rewardType' => $item->rewardType,
- 'targetId' => $item->targetId,
- 'quantity' => $item->quantity,
- 'sourceType' => $sourceType,
- 'sourceId' => $sourceId
- ]);
- break;
- }
- }
- /**
- * 记录奖励日志
- *
- * @param int $userId 用户ID
- * @param int $groupId 奖励组ID
- * @param string $sourceType 来源类型
- * @param int $sourceId 来源ID
- * @param RewardItemDto[] $items 发放的奖励项
- * @return GameRewardLog
- */
- private function logReward(int $userId, int $groupId, string $sourceType, int $sourceId, array $items): GameRewardLog
- {
- // 将DTO转换为可存储的数组
- $itemsData = array_map(function (RewardItemDto $item) {
- return [
- 'id' => $item->id,
- 'reward_type' => $item->rewardType,
- 'target_id' => $item->targetId,
- 'param1' => $item->param1,
- 'param2' => $item->param2,
- 'quantity' => $item->quantity,
- 'extra_data' => $item->extraData
- ];
- }, $items);
- // 创建日志记录
- return GameRewardLog::create([
- 'user_id' => $userId,
- 'group_id' => $groupId,
- 'source_type' => $sourceType,
- 'source_id' => $sourceId,
- 'reward_items' => $itemsData
- ]);
- }
- /**
- * 处理物品奖励
- *
- * @param int $userId 用户ID
- * @param RewardItemDto $item 奖励项
- * @param string $sourceType 来源类型
- * @param int $sourceId 来源ID
- * @return void
- * @throws Exception
- */
- private function processItemReward(int $userId, RewardItemDto $item, string $sourceType, int $sourceId): void
- {
- try {
- // 发放物品奖励,传递来源信息
- ItemService::addItem($userId, $item->targetId, $item->quantity, [
- 'param1' => $item->param1,
- 'param2' => $item->param2,
- 'source_type' => $sourceType,
- 'source_id' => $sourceId,
- 'source' => 'reward', // 保持向后兼容
- 'extra_data' => $item->extraData
- ]);
- Log::info("物品奖励发放成功", [
- 'userId' => $userId,
- 'itemId' => $item->targetId,
- 'quantity' => $item->quantity,
- 'sourceType' => $sourceType,
- 'sourceId' => $sourceId
- ]);
- } catch (Exception $e) {
- Log::error("物品奖励发放失败", [
- 'userId' => $userId,
- 'itemId' => $item->targetId,
- 'quantity' => $item->quantity,
- 'sourceType' => $sourceType,
- 'sourceId' => $sourceId,
- 'error' => $e->getMessage()
- ]);
- throw new Exception("物品奖励发放失败: " . $e->getMessage());
- }
- }
- /**
- * 处理账户种类奖励(FUND_CONFIG)
- *
- * @param int $userId 用户ID
- * @param RewardItemDto $item 奖励项
- * @param string $sourceType 来源类型
- * @param int $sourceId 来源ID
- * @return void
- * @throws Exception
- */
- private function processFundConfigReward(int $userId, RewardItemDto $item, string $sourceType, int $sourceId): void
- {
- try {
- // 使用Fund模块的User类来处理资金变更
- // target_id 是 fund_config 表的 id(账户种类ID)
- $result = \App\Module\Fund\Logic\User::handle(
- $userId,
- $item->targetId, // fund_config_id
- $item->quantity, // 金额
- \App\Module\Fund\Enums\LOG_TYPE::TRADE, // 日志类型为贸易
- $sourceId, // 关联ID,使用来源ID
- "奖励发放:账户种类奖励 - {$sourceType}#{$sourceId}"
- );
- if (is_string($result)) {
- throw new Exception("账户种类奖励发放失败: " . $result);
- }
- Log::info("账户种类奖励发放成功", [
- 'userId' => $userId,
- 'fundConfigId' => $item->targetId,
- 'amount' => $item->quantity,
- 'sourceType' => $sourceType,
- 'sourceId' => $sourceId
- ]);
- } catch (Exception $e) {
- Log::error("账户种类奖励发放失败", [
- 'userId' => $userId,
- 'fundConfigId' => $item->targetId,
- 'amount' => $item->quantity,
- 'sourceType' => $sourceType,
- 'sourceId' => $sourceId,
- 'error' => $e->getMessage()
- ]);
- throw new Exception("账户种类奖励发放失败: " . $e->getMessage());
- }
- }
- /**
- * 处理币种奖励(CURRENCY)
- *
- * @param int $userId 用户ID
- * @param RewardItemDto $item 奖励项
- * @param string $sourceType 来源类型
- * @param int $sourceId 来源ID
- * @return void
- * @throws Exception
- */
- private function processCurrencyReward(int $userId, RewardItemDto $item, string $sourceType, int $sourceId): void
- {
- try {
- // 对于币种奖励,需要先根据币种ID找到对应的账户种类ID
- // 这里需要查询 fund_config 表,找到对应币种的账户种类
- $fundConfig = \App\Module\Fund\Models\FundConfigModel::where('currency_id', $item->targetId)->first();
- if (!$fundConfig) {
- throw new Exception("找不到币种ID为 {$item->targetId} 的账户配置");
- }
- // 使用找到的账户种类ID来发放奖励
- $result = \App\Module\Fund\Logic\User::handle(
- $userId,
- $fundConfig->id, // fund_config_id
- $item->quantity, // 金额
- \App\Module\Fund\Enums\LOG_TYPE::TRADE, // 日志类型
- $sourceId, // 关联ID,使用来源ID
- "奖励发放:币种奖励 - {$sourceType}#{$sourceId}"
- );
- if (is_string($result)) {
- throw new Exception("币种奖励发放失败: " . $result);
- }
- Log::info("币种奖励发放成功", [
- 'userId' => $userId,
- 'currencyId' => $item->targetId,
- 'fundConfigId' => $fundConfig->id,
- 'amount' => $item->quantity,
- 'sourceType' => $sourceType,
- 'sourceId' => $sourceId
- ]);
- } catch (Exception $e) {
- Log::error("币种奖励发放失败", [
- 'userId' => $userId,
- 'currencyId' => $item->targetId,
- 'amount' => $item->quantity,
- 'sourceType' => $sourceType,
- 'sourceId' => $sourceId,
- 'error' => $e->getMessage()
- ]);
- throw new Exception("币种奖励发放失败: " . $e->getMessage());
- }
- }
- /**
- * 处理宠物经验奖励
- *
- * @param int $userId 用户ID
- * @param RewardItemDto $item 奖励项
- * @param string $sourceType 来源类型
- * @param int $sourceId 来源ID
- * @return void
- * @throws Exception
- */
- private function processPetExpReward(int $userId, RewardItemDto $item, string $sourceType, int $sourceId): void
- {
- try {
- // 获取用户的宠物
- $pet = \App\Module\Pet\Models\PetUser::where('user_id', $userId)
- ->where('id', $item->targetId)
- ->first();
- if (!$pet) {
- throw new Exception("找不到ID为 {$item->targetId} 的宠物");
- }
- // 使用宠物逻辑类来增加经验
- $petLogic = new \App\Module\Pet\Logic\PetLogic();
- $reflection = new \ReflectionClass($petLogic);
- $method = $reflection->getMethod('addExperience');
- $method->setAccessible(true);
- $levelUpOccurred = $method->invoke($petLogic, $item->targetId, $item->quantity);
- Log::info("宠物经验奖励发放成功", [
- 'userId' => $userId,
- 'petId' => $item->targetId,
- 'expAmount' => $item->quantity,
- 'levelUp' => $levelUpOccurred,
- 'sourceType' => $sourceType,
- 'sourceId' => $sourceId
- ]);
- } catch (Exception $e) {
- Log::error("宠物经验奖励发放失败", [
- 'userId' => $userId,
- 'petId' => $item->targetId,
- 'expAmount' => $item->quantity,
- 'sourceType' => $sourceType,
- 'sourceId' => $sourceId,
- 'error' => $e->getMessage()
- ]);
- throw new Exception("宠物经验奖励发放失败: " . $e->getMessage());
- }
- }
- /**
- * 处理宠物体力奖励
- *
- * @param int $userId 用户ID
- * @param RewardItemDto $item 奖励项
- * @param string $sourceType 来源类型
- * @param int $sourceId 来源ID
- * @return void
- * @throws Exception
- */
- private function processPetEnergyReward(int $userId, RewardItemDto $item, string $sourceType, int $sourceId): void
- {
- try {
- // 获取用户的宠物
- $pet = \App\Module\Pet\Models\PetUser::where('user_id', $userId)
- ->where('id', $item->targetId)
- ->first();
- if (!$pet) {
- throw new Exception("找不到ID为 {$item->targetId} 的宠物");
- }
- // 使用宠物逻辑类来增加体力
- $petLogic = new \App\Module\Pet\Logic\PetLogic();
- $reflection = new \ReflectionClass($petLogic);
- $method = $reflection->getMethod('addStamina');
- $method->setAccessible(true);
- $actualGained = $method->invoke($petLogic, $item->targetId, $item->quantity);
- Log::info("宠物体力奖励发放成功", [
- 'userId' => $userId,
- 'petId' => $item->targetId,
- 'staminaAmount' => $item->quantity,
- 'actualGained' => $actualGained,
- 'sourceType' => $sourceType,
- 'sourceId' => $sourceId
- ]);
- } catch (Exception $e) {
- Log::error("宠物体力奖励发放失败", [
- 'userId' => $userId,
- 'petId' => $item->targetId,
- 'staminaAmount' => $item->quantity,
- 'sourceType' => $sourceType,
- 'sourceId' => $sourceId,
- 'error' => $e->getMessage()
- ]);
- throw new Exception("宠物体力奖励发放失败: " . $e->getMessage());
- }
- }
- /**
- * 处理神像奖励(农场buff)
- *
- * @param int $userId 用户ID
- * @param RewardItemDto $item 奖励项
- * @param string $sourceType 来源类型
- * @param int $sourceId 来源ID
- * @return void
- * @throws Exception
- */
- private function processFarmShrineReward(int $userId, RewardItemDto $item, string $sourceType, int $sourceId): void
- {
- try {
- // 获取神像类型和持续时间
- $shrineType = $item->targetId; // 神像类型(1=丰收之神,2=雨露之神,3=屠草之神,4=拭虫之神)
- $durationHours = $item->param2 > 0 ? $item->param2 : 24; // 持续时间(小时),默认24小时
- $activationCount = $item->quantity > 0 ? $item->quantity : 1; // 激活次数,默认1次
- // 验证神像类型是否有效
- if (!in_array($shrineType, [1, 2, 3, 4])) {
- throw new Exception("无效的神像类型: {$shrineType}");
- }
- // 验证用户是否存在
- $farmUser = \App\Module\Farm\Models\FarmUser::where('user_id', $userId)->first();
- if (!$farmUser) {
- throw new Exception("用户农场数据不存在,用户ID: {$userId}");
- }
- // 循环激活神像(支持多次激活)
- for ($i = 0; $i < $activationCount; $i++) {
- // 使用BuffService激活神像
- $buff = \App\Module\Farm\Services\BuffService::activateBuff($userId, $shrineType, $durationHours);
- if (!$buff) {
- throw new Exception("神像激活失败,神像类型: {$shrineType},用户ID: {$userId}");
- }
- Log::info("神像奖励激活成功", [
- 'userId' => $userId,
- 'shrineType' => $shrineType,
- 'shrineName' => \App\Module\Farm\Enums\BUFF_TYPE::getName($shrineType),
- 'durationHours' => $durationHours,
- 'activationIndex' => $i + 1,
- 'totalActivations' => $activationCount,
- 'expireTime' => $buff->expire_time ? $buff->expire_time->toDateTimeString() : null,
- 'sourceType' => $sourceType,
- 'sourceId' => $sourceId
- ]);
- }
- Log::info("神像奖励发放完成", [
- 'userId' => $userId,
- 'shrineType' => $shrineType,
- 'shrineName' => \App\Module\Farm\Enums\BUFF_TYPE::getName($shrineType),
- 'durationHours' => $durationHours,
- 'totalActivations' => $activationCount,
- 'sourceType' => $sourceType,
- 'sourceId' => $sourceId
- ]);
- } catch (Exception $e) {
- Log::error("神像奖励发放失败", [
- 'userId' => $userId,
- 'shrineType' => $item->targetId,
- 'durationHours' => $item->param2,
- 'quantity' => $item->quantity,
- 'sourceType' => $sourceType,
- 'sourceId' => $sourceId,
- 'error' => $e->getMessage()
- ]);
- throw new Exception("神像奖励发放失败: " . $e->getMessage());
- }
- }
- /**
- * 处理其他类型奖励
- *
- * @param int $userId 用户ID
- * @param RewardItemDto $item 奖励项
- * @param string $sourceType 来源类型
- * @param int $sourceId 来源ID
- * @return void
- */
- private function processOtherReward(int $userId, RewardItemDto $item, string $sourceType, int $sourceId): void
- {
- // 其他类型奖励的处理逻辑
- // 这里可以根据具体需求实现,比如称号、成就等
- Log::info("其他类型奖励处理", [
- 'userId' => $userId,
- 'rewardType' => $item->rewardType,
- 'targetId' => $item->targetId,
- 'quantity' => $item->quantity,
- 'param1' => $item->param1,
- 'param2' => $item->param2,
- 'extraData' => $item->extraData,
- 'sourceType' => $sourceType,
- 'sourceId' => $sourceId
- ]);
- // 目前只记录日志,具体实现可以根据业务需求扩展
- // 例如:
- // - 称号奖励:更新用户称号
- // - 成就奖励:解锁成就
- // - 特殊权限:更新用户权限
- }
- }
|