title($this->title) ->description('查看用户的农场信息汇总') ->body($this->grid()); } /** * 查看指定用户的农场信息汇总 * * @param int $userId 用户ID * @param Content $content * @return Content */ #[Get('farm-user-summary/{userId}', name: 'dcat.admin.farm-user-summary.show1')] public function show($userId, Content $content) { // 记录请求信息 \Illuminate\Support\Facades\Log::info('访问农场用户信息汇总', [ 'user_id' => $userId, 'referer' => request()->header('referer'), 'user_agent' => request()->header('user-agent'), 'ip' => request()->ip(), 'url' => request()->fullUrl(), ]); // 查找用户 $user = User::find($userId); if (!$user) { admin_error('错误', "用户 {$userId} 不存在"); \Illuminate\Support\Facades\Log::warning('访问不存在的用户', [ 'user_id' => $userId ]); return admin_redirect('farm-user-summary'); } // 检查是否存在农场用户记录 $farmUser = FarmUser::where('user_id', $userId)->first(); if (!$farmUser) { admin_warning('提示', "用户 {$userId} 没有农场信息"); \Illuminate\Support\Facades\Log::info('用户没有农场信息', [ 'user_id' => $userId ]); // 不重定向,继续显示用户信息,只是提示没有农场信息 } return $content ->title($this->title) ->description("用户 {$user->username}(ID: {$user->id})的农场信息汇总") ->body(function (Row $row) use ($user) { // 第一行:用户基本信息和房屋信息 $row->column(6, $this->userInfoCard($user)); $row->column(6, $this->houseInfoCard($user->id)); // 第二行:土地信息和作物信息 $row->column(12, $this->landInfoCard($user->id)); // 第三行:物品信息 $row->column(12, $this->itemInfoCard($user->id)); // 第四行:代币信息 $row->column(12, $this->fundInfoCard($user->id)); // 第五行:宠物信息 $row->column(12, $this->petInfoCard($user->id)); // 第六行:宠物生活技能情况 $row->column(12, $this->petLifeSkillsCard($user->id)); // 第七行:神像buff信息 $row->column(12, $this->buffInfoCard($user->id)); }); } /** * 用户基本信息卡片 * * @param User $user 用户对象 * @return Card */ protected function userInfoCard(User $user) { $userInfo = $user->info; $avatar = $userInfo ? $userInfo->avatar : ''; $nickname = $userInfo ? $userInfo->nickname : ''; $content = <<

用户ID:{$user->id}

用户名:{$user->username}

昵称:{$nickname}

注册时间:{$user->created_at}

HTML; return new Card('用户基本信息', $content); } /** * 房屋信息卡片 * * @param int $userId 用户ID * @return Card */ protected function houseInfoCard($userId) { // 获取用户的农场信息 $farmUser = FarmUser::where('user_id', $userId)->first(); if (!$farmUser) { return new Card('房屋信息', new Alert('warning', '该用户没有农场信息')); } // 获取房屋配置信息 $houseConfig = FarmHouseConfig::where('level', $farmUser->house_level)->first(); if (!$houseConfig) { return new Card('房屋信息', new Alert('warning', "找不到房屋等级 {$farmUser->house_level} 的配置信息")); } $content = <<

房屋等级:{$farmUser->house_level}

最后升级时间:{$farmUser->last_upgrade_time}

产出加成:{$houseConfig->output_bonus}

特殊土地上限:{$houseConfig->special_land_limit}

可用土地数量:{$houseConfig->available_lands}

HTML; // 如果有降级天数,显示降级信息 if ($houseConfig->downgrade_days) { $content .= "

降级天数:{$houseConfig->downgrade_days}

"; } $content .= <<
查看房屋配置
HTML; return new Card('房屋信息', $content); } /** * 土地信息卡片 * * @param int $userId 用户ID * @return Card */ protected function landInfoCard($userId) { // 获取用户的土地信息 /** * @var FarmLand $land */ $lands = FarmLand::with([ 'landType', 'crop.seed' ]) ->where('user_id', $userId) ->get(); if ($lands->isEmpty()) { return new Card('土地信息', new Alert('warning', '该用户没有土地信息')); } // 土地类型统计 $landTypeStats = $lands->groupBy('land_type')->map->count(); // 土地状态统计 $landStatusStats = $lands->groupBy('status')->map->count(); // 灾害统计 $disasterStats = [ 1 => 0, // 干旱 2 => 0, // 虫害 3 => 0, // 杂草 ]; // 统计活跃的灾害 foreach ($lands as $land) { if ($land->crop && !empty($land->crop->disasters)) { foreach ($land->crop->disasters as $disaster) { if (($disaster['status'] ?? '') === 'active') { $type = $disaster['type'] ?? 0; if (isset($disasterStats[$type])) { $disasterStats[$type]++; } } } } } // 创建土地类型、状态和灾害的统计表格 $statsContent = '
'; // 土地类型统计 $statsContent .= '
'; $statsContent .= '
土地类型统计
'; $statsContent .= ''; $statsContent .= ''; $statsContent .= ''; $landTypeNames = [ 1 => '普通土地', 2 => '红土地', 3 => '黑土地', 4 => '金土地', 5 => '蓝土地', 6 => '紫土地', ]; foreach ($landTypeStats as $typeId => $count) { $typeName = $landTypeNames[$typeId] ?? "类型{$typeId}"; $statsContent .= ""; } $statsContent .= '
土地类型数量
{$typeName}{$count}
'; // 土地状态统计 $statsContent .= '
'; $statsContent .= '
土地状态统计
'; $statsContent .= ''; $statsContent .= ''; $statsContent .= ''; $landStatusNames = [ 0 => '空闲', 1 => '种植中', 2 => '灾害', 3 => '可收获', 4 => '枯萎', ]; foreach ($landStatusStats as $statusId => $count) { $statusName = $landStatusNames[$statusId] ?? "状态{$statusId}"; $statsContent .= ""; } $statsContent .= '
土地状态数量
{$statusName}{$count}
'; // 灾害统计 $statsContent .= '
'; $statsContent .= '
灾害统计
'; $statsContent .= ''; $statsContent .= ''; $statsContent .= ''; $disasterNames = DISASTER_TYPE::getAll(); $totalDisasters = 0; $d = DisasterService::getAllDisasters(); foreach ($disasterStats as $typeId => $count) { $typeName = $disasterNames[$typeId] ?? "未知灾害{$typeId}"; $penalty = $d[$typeId]; $totalDisasters += $count; $statsContent .= ""; } // 添加总计行 $totalPenalty = $totalDisasters > 0 ? ($totalDisasters * 5) . '%' : '0%'; $statsContent .= ""; $statsContent .= '
灾害类型数量减产比例
{$typeName}{$count}{$penalty}
总计{$totalDisasters}{$totalPenalty}
'; $statsContent .= '
'; // 创建土地详情表格 $headers = [ 'ID', '位置', '土地类型', '状态', '种植作物', '种植时间', '生长阶段', '本阶段开始时间', '本阶段结束时间(剩余)', '果实信息', '灾害情况' ]; $rows = []; foreach ($lands as $land) { $landType = $land->landType ? $land->landType->name : "类型{$land->land_type}"; $status = $landStatusNames[$land->status] ?? "状态{$land->status}"; /** * @var FarmCrop $crop */ $crop = $land->crop; $cropInfo = '无'; $plantTime = ''; $growthStage = ''; $stageStartTime = ''; $stageEndTime = ''; $fruitInfo = '无'; $disasterInfo = '无'; if ($crop) { $seedName = $crop->seed ? $crop->seed->name : "种子{$crop->seed_id}"; $cropInfo = $seedName; $plantTime = $crop->plant_time; $growthStage = $this->getGrowthStageName($crop->growth_stage); $stageStartTime = $crop->stage_start_time; $stageEndTime = $this->formatRelativeTime($crop->stage_end_time); // 处理果实信息 if ($crop->final_output_item_id) { $fruitInfo = $this->getFruitInfo($crop->final_output_item_id,$crop->final_output_amount); } else { // 如果还没有确定最终产出,显示种子的可能产出 if ($crop->seed && $crop->seed->outputs) { $fruitInfo = $this->getSeedPossibleOutputs($crop->seed); } } // 处理灾害信息 if (!empty($crop->disasters)) { $disasterInfo = $this->formatDisasterInfo($crop->disasters); } } $rows[] = [ $land->id, $land->position, $landType, $status, $cropInfo, $plantTime, $growthStage, $stageStartTime, $stageEndTime, $fruitInfo, $disasterInfo, ]; } $table = new Table($headers, $rows); $content = $statsContent . '
' . $table->render() . '
'; $content .= <<
查看土地详情 查看作物详情
HTML; return new Card('土地信息', $content); } /** * 获取生长阶段名称 * * @param GROWTH_STAGE|int $stage 生长阶段枚举或整数值 * @return string 生长阶段名称 */ protected function getGrowthStageName($stage) { // 如果传入的是整数,转换为枚举 if (is_int($stage)) { try { $stage = GROWTH_STAGE::from($stage); } catch (\ValueError) { return "未知阶段{$stage}"; } } // 如果是null,返回未知 if ($stage === null) { return "未知阶段"; } // 获取阶段名称 try { $stageNames = GROWTH_STAGE::getAll(); $stageValue = $stage->value; return $stageNames[$stageValue] ?? "阶段{$stageValue}"; } catch (\Throwable) { return "错误阶段"; } } /** * 格式化相对时间描述 * * @param string|\Carbon\Carbon|null $dateTime 时间 * @return string 相对时间描述 */ protected function formatRelativeTime($dateTime): string { if (!$dateTime) { return '无'; } try { // 确保是Carbon实例 if (is_string($dateTime)) { $dateTime = \Carbon\Carbon::parse($dateTime); } $now = now(); // 如果时间已经过去 if ($dateTime->isPast()) { return '已过期'; } // 计算时间差 $diffInSeconds = $now->diffInSeconds($dateTime); $diffInMinutes = $now->diffInMinutes($dateTime); $diffInHours = $now->diffInHours($dateTime); $diffInDays = $now->diffInDays($dateTime); // 根据时间差返回合适的描述 if ($diffInSeconds < 60) { $seconds = round($diffInSeconds); return "{$seconds}秒后"; } elseif ($diffInMinutes < 60) { $minutes = round($diffInMinutes); return "{$minutes}分钟后"; } elseif ($diffInHours < 24) { // 小时显示保留1位小数,但如果是整数则不显示小数 $hours = round($diffInHours, 1); $hoursDisplay = $hours == intval($hours) ? intval($hours) : $hours; return "{$hoursDisplay}小时后"; } elseif ($diffInDays < 7) { $days = round($diffInDays); return "{$days}天后"; } else { // 超过7天显示具体日期 return $dateTime->format('Y-m-d H:i:s'); } } catch (\Throwable $e) { return '时间格式错误'; } } /** * 物品信息卡片 * * @param int $userId 用户ID * @return Card */ protected function itemInfoCard($userId) { // 获取用户的物品信息 $items = ItemUser::with('item') ->where('user_id', $userId) ->orderBy('quantity', 'desc') ->limit(20) ->get(); if ($items->isEmpty()) { return new Card('物品信息', new Alert('warning', '该用户没有物品信息')); } // 创建物品表格 $headers = [ '物品ID', '物品名称', '数量', '物品类型', '过期时间' ]; $rows = []; foreach ($items as $item) { $itemName = $item->item ? $item->item->name : "物品{$item->item_id}"; $itemType = $item->item ? $this->getItemTypeName($item->item->type) : ''; $rows[] = [ $item->item_id, $itemName, $item->quantity, $itemType, $item->expire_at ?: '永久', ]; } $table = new Table($headers, $rows); // 获取用户物品总数 $totalCount = ItemUser::where('user_id', $userId)->count(); $content = << 用户共有 {$totalCount} 种物品,下表显示数量最多的前20种物品 {$table->render()}
查看物品详情
HTML; return new Card('物品信息', $content); } /** * 获取物品类型名称 * * @param ITEM_TYPE|int $type 物品类型枚举或整数值 * @return string 物品类型名称 */ protected function getItemTypeName($type) { // 如果传入的是整数,转换为枚举 if (is_int($type)) { try { $type = ITEM_TYPE::from($type); } catch (\ValueError) { return "未知类型{$type}"; } } // 如果是null,返回未知 if ($type === null) { return "未知类型"; } // 获取类型名称 try { $typeNames = ITEM_TYPE::getValueDescription(); $typeValue = $type->value; return $typeNames[$typeValue] ?? "类型{$typeValue}"; } catch (\Throwable) { return "错误类型"; } } /** * 格式化灾害信息 * * @param array $disasters 灾害数组 * @return string 格式化后的灾害信息 */ protected function formatDisasterInfo(array $disasters): string { if (empty($disasters)) { return '无'; } $result = []; foreach ($disasters as $disaster) { $type = $disaster['type'] ?? 0; $status = $disaster['status'] ?? 'active'; // 默认为活跃状态 // 获取灾害类型名称 $typeName = DISASTER_TYPE::getName($type); // 灾害状态 $statusText = $status === 'active' ? '活跃' : '已处理'; // 灾害开始时间 $startTime = isset($disaster['start_time']) ? date('Y-m-d H:i:s', $disaster['start_time']) : '未知'; // 灾害结束时间(如果有) $endTime = ''; if (isset($disaster['end_time']) && $disaster['end_time'] > 0) { $endTime = date('Y-m-d H:i:s', $disaster['end_time']); } // 减产比例 - 从DisasterService获取默认值 $defaultPenalties = \App\Module\Farm\Services\DisasterService::getAllDisasters(); $defaultPenalty = $defaultPenalties[$type] ?? 0.05; $penalty = isset($disaster['penalty']) ? ($disaster['penalty'] * 100) . '%' : ($defaultPenalty * 100) . '%'; // 组合灾害信息 $disasterInfo = "
{$typeName}: {$statusText}
"; $disasterInfo .= "
开始: {$startTime}
"; if ($endTime) { $disasterInfo .= "
结束: {$endTime}
"; } $disasterInfo .= "
减产: {$penalty}
"; // 如果有额外的灾害信息,也显示出来 if (isset($disaster['id'])) { $disasterInfo .= "
ID: {$disaster['id']}
"; } $result[] = $disasterInfo; } return implode('
', $result); } /** * 代币信息卡片 * * @param int $userId 用户ID * @return Card */ protected function fundInfoCard($userId) { // 获取用户的代币信息 $funds = FundModel::where('user_id', $userId)->get(); if ($funds->isEmpty()) { return new Card('代币信息', new Alert('warning', '该用户没有代币信息')); } // 获取资金类型名称映射 $fundNames = AccountService::getFundsDesc(); // 创建代币表格 $headers = [ '账户ID', '账户名称', '余额', '更新时间' ]; $rows = []; foreach ($funds as $fund) { try { $fundIdValue = $fund->fund_id->value(); $fundName = $fundNames[$fundIdValue] ?? "账户{$fundIdValue}"; $balance = $fund->balance; $rows[] = [ $fundIdValue, $fundName, $balance, $fund->update_time ? date('Y-m-d H:i:s', $fund->update_time) : '', ]; } catch (\Throwable) { // 如果出现异常,添加一个错误行 $rows[] = [ $fund->id ?? '未知', '数据错误', $fund->balance ?? '未知', $fund->update_time ? date('Y-m-d H:i:s', $fund->update_time) : '', ]; } } $table = new Table($headers, $rows); $content = <<render()}
查看账户详情
HTML; return new Card('代币信息', $content); } /** * 宠物信息卡片 * * @param int $userId 用户ID * @return Card */ protected function petInfoCard($userId) { // 获取用户的宠物信息 $pets = PetUser::where('user_id', $userId) ->orderBy('level', 'desc') ->orderBy('id', 'desc') // 品阶功能已废弃,改为按ID排序 ->get(); if ($pets->isEmpty()) { return new Card('宠物信息', new Alert('warning', '该用户没有宠物信息')); } // 宠物统计 $totalPets = $pets->count(); // 品阶功能已废弃,不再统计grade $statusStats = $pets->groupBy('status')->map->count(); $levelStats = [ 'max_level' => $pets->max('level'), 'avg_level' => round($pets->avg('level'), 1), 'total_exp' => $pets->sum('experience'), ]; // 创建宠物表格 $headers = ['宠物ID','宠物名称', '等级', '经验', '体力', '状态', '创建时间']; // 移除品阶列 $rows = []; // 品阶功能已废弃,移除gradeNames数组 $statusNames = [ PetStatus::NONE->value => '未知', PetStatus::NORMAL->value => '正常', PetStatus::FIGHTING->value => '战斗中', PetStatus::DEAD->value => '死亡', PetStatus::FEEDING->value => '喂养中', PetStatus::TRAINING->value => '训练中', PetStatus::RESTING->value => '休息中', PetStatus::TRAVELING->value => '外出中', ]; foreach ($pets as $pet) { try { // 品阶功能已废弃,移除gradeName相关代码 $statusName = $statusNames[$pet->status->value] ?? "状态{$pet->status->value}"; // 状态颜色 $statusBadge = match($pet->status) { PetStatus::NORMAL => '' . $statusName . '', PetStatus::FIGHTING => '' . $statusName . '', PetStatus::DEAD => '' . $statusName . '', PetStatus::FEEDING, PetStatus::TRAINING => '' . $statusName . '', PetStatus::RESTING, PetStatus::TRAVELING => '' . $statusName . '', default => '' . $statusName . '', }; $rows[] = [ $pet->id, $pet->name, // 移除品阶列 $pet->level, $pet->experience, $pet->stamina, $statusBadge, $pet->created_at->format('Y-m-d H:i:s'), ]; } catch (\Throwable) { // 如果出现异常,添加一个错误行 $rows[] = [ $pet->name ?? '未知', '数据错误', $pet->level ?? 0, $pet->experience ?? 0, $pet->stamina ?? 0, '数据错误', $pet->created_at ? $pet->created_at->format('Y-m-d H:i:s') : '未知', ]; } } $table = new Table($headers, $rows); // 统计信息 $statsHtml = '
'; $statsHtml .= '
宠物总数: ' . $totalPets . '
'; $statsHtml .= '
最高等级: ' . $levelStats['max_level'] . '
'; $statsHtml .= '
平均等级: ' . $levelStats['avg_level'] . '
'; $statsHtml .= '
总经验: ' . number_format($levelStats['total_exp']) . '
'; $statsHtml .= '
'; // 品阶功能已废弃,移除品阶统计 // 状态统计 if (!$statusStats->isEmpty()) { $statsHtml .= '
状态分布: '; foreach ($statusStats as $status => $count) { $statusName = $statusNames[$status] ?? "状态{$status}"; $statsHtml .= "{$statusName}: {$count}只 "; } $statsHtml .= '
'; } $content = $statsHtml . $table->render(); return new Card('宠物信息', $content); } /** * 宠物生活技能情况卡片 * * @param int $userId 用户ID * @return Card */ protected function petLifeSkillsCard($userId) { // 获取用户的宠物 $pets = PetUser::where('user_id', $userId)->get(); if ($pets->isEmpty()) { return new Card('宠物生活技能情况', new Alert('warning', '该用户没有宠物,无法使用生活技能')); } // 获取所有宠物的激活技能 $petIds = $pets->pluck('id')->toArray(); $activeSkills = PetActiveSkill::with(['pet', 'skill']) ->whereIn('pet_id', $petIds) ->orderBy('status', 'asc') ->orderBy('end_time', 'desc') ->get(); // 统计信息 $totalSkills = $activeSkills->count(); $activeCount = $activeSkills->where('status', 'active')->count(); $expiredCount = $activeSkills->where('status', 'expired')->count(); $cancelledCount = $activeSkills->where('status', 'cancelled')->count(); // 技能类型统计 $skillTypeStats = $activeSkills->groupBy('skill_name')->map->count(); // 创建统计信息 $statsHtml = '
'; $statsHtml .= '
总技能使用次数: ' . $totalSkills . '
'; $statsHtml .= '
当前激活: ' . $activeCount . '
'; $statsHtml .= '
已过期: ' . $expiredCount . '
'; $statsHtml .= '
已取消: ' . $cancelledCount . '
'; $statsHtml .= '
'; // 技能类型统计 if (!$skillTypeStats->isEmpty()) { $statsHtml .= '
技能使用统计: '; foreach ($skillTypeStats as $skillName => $count) { $statsHtml .= "{$skillName}: {$count}次 "; } $statsHtml .= '
'; } if ($activeSkills->isEmpty()) { $content = $statsHtml . '
该用户的宠物还没有使用过生活技能
'; // 即使没有激活技能,也显示历史使用记录 $content .= $this->getRecentSkillUsageSection($petIds); return new Card('宠物生活技能情况', $content); } // 创建技能详情表格 $headers = ['宠物名称', '技能名称', '开始时间', '结束时间', '状态', '剩余时间', '技能配置']; $rows = []; foreach ($activeSkills as $activeSkill) { try { $petName = $activeSkill->pet ? $activeSkill->pet->name : "宠物{$activeSkill->pet_id}"; $skillName = $activeSkill->skill_name; $startTime = $activeSkill->start_time->format('Y-m-d H:i:s'); $endTime = $activeSkill->end_time->format('Y-m-d H:i:s'); // 状态显示 - 实时检查过期状态 $isReallyActive = $activeSkill->status === 'active' && $activeSkill->end_time > now(); $statusBadge = match(true) { $activeSkill->status === 'cancelled' => '已取消', $isReallyActive => '生效中', default => '已过期', }; // 剩余时间 - 实时计算 $remainingTime = ''; if ($isReallyActive) { $remaining = $activeSkill->getRemainingSeconds(); if ($remaining > 0) { $hours = floor($remaining / 3600); $minutes = floor(($remaining % 3600) / 60); $seconds = $remaining % 60; $remainingTime = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds); } else { $remainingTime = '已过期'; } } else { $remainingTime = '-'; } // 技能配置信息 $configInfo = ''; if (!empty($activeSkill->config)) { $config = $activeSkill->config; $configItems = []; // 显示关键配置信息 if (isset($config['check_interval'])) { $configItems[] = "检查间隔: {$config['check_interval']}秒"; } if (isset($config['preferred_seeds']) && !empty($config['preferred_seeds'])) { $seedCount = count($config['preferred_seeds']); $configItems[] = "优先种子: {$seedCount}种"; } if (isset($config['protected_types']) && !empty($config['protected_types'])) { $protectedTypes = implode(', ', $config['protected_types']); $configItems[] = "防护类型: {$protectedTypes}"; } if (isset($config['statistics']) && !empty($config['statistics'])) { $statsCount = count($config['statistics']); $configItems[] = "执行记录: {$statsCount}次"; } $configInfo = implode('
', $configItems); } $rows[] = [ $petName, $skillName, $startTime, $endTime, $statusBadge, $remainingTime, $configInfo ?: '-' ]; } catch (\Throwable $e) { // 如果出现异常,添加一个错误行 $rows[] = [ $activeSkill->pet ? $activeSkill->pet->name : '未知', $activeSkill->skill_name ?? '未知', $activeSkill->start_time ? $activeSkill->start_time->format('Y-m-d H:i:s') : '未知', $activeSkill->end_time ? $activeSkill->end_time->format('Y-m-d H:i:s') : '未知', '数据错误', '-', '数据解析错误' ]; } } $table = new Table($headers, $rows); $content = $statsHtml . $table->render(); // 添加最近10次技能使用记录 $content .= $this->getRecentSkillUsageSection($petIds); // 添加说明信息 $content .= '
'; $content .= '说明:
'; $content .= '• 自动收菜:每分钟自动收获成熟的作物
'; $content .= '• 自动播种:每分钟自动在空闲土地上播种
'; $content .= '• 灾害防护:每5分钟检查并自动清除作物灾害
'; $content .= '• 所有自动操作仍需消耗相应的道具(种子、化肥等)'; $content .= '
'; return new Card('宠物生活技能情况', $content); } /** * 获取最近技能使用记录区域 * * @param array $petIds 宠物ID数组 * @return string HTML内容 */ protected function getRecentSkillUsageSection(array $petIds): string { if (empty($petIds)) { return ''; } // 获取最近10次技能使用记录 $recentLogs = PetSkillLog::with(['pet', 'skill']) ->whereIn('pet_id', $petIds) ->orderBy('used_at', 'desc') ->limit(10) ->get(); if ($recentLogs->isEmpty()) { return '
最近技能使用记录
暂无技能使用记录
'; } // 创建技能使用记录表格 $headers = ['使用时间', '宠物名称', '技能名称', '体力消耗', '技能效果', '状态']; $rows = []; foreach ($recentLogs as $log) { try { $petName = $log->pet ? $log->pet->name : "宠物{$log->pet_id}"; $skillName = $log->skill ? $log->skill->skill_name : "技能{$log->skill_id}"; // 安全处理时间格式 $usedAt = '未知时间'; if ($log->used_at) { try { if ($log->used_at instanceof \Carbon\Carbon) { $usedAt = $log->used_at->format('Y-m-d H:i:s'); } else { // 尝试解析字符串时间 $usedAt = date('Y-m-d H:i:s', strtotime($log->used_at)); } } catch (\Exception $e) { $usedAt = (string) $log->used_at; } } $staminaCost = $log->skill ? $log->skill->stamina_cost : '-'; // 解析技能效果结果 $effectResult = ''; $status = '成功'; if (!empty($log->effect_result)) { try { $effectData = json_decode($log->effect_result, true); if (is_array($effectData)) { $effectItems = []; // 根据技能类型显示不同的效果信息 if (isset($effectData['skill_type'])) { $effectItems[] = "类型: {$effectData['skill_type']}"; } if (isset($effectData['duration'])) { $hours = round($effectData['duration'] / 3600, 1); $effectItems[] = "持续: {$hours}小时"; } if (isset($effectData['end_time'])) { $endTime = date('H:i', strtotime($effectData['end_time'])); $effectItems[] = "结束: {$endTime}"; } if (isset($effectData['message'])) { $effectItems[] = $effectData['message']; } // 检查是否有错误 if (isset($effectData['success']) && $effectData['success'] === false) { $status = '失败'; if (isset($effectData['message'])) { $effectItems = [$effectData['message']]; } } $effectResult = implode('
', $effectItems); } else { $effectResult = $log->effect_result; } } catch (\Exception $e) { $effectResult = '数据解析错误'; $status = '异常'; } } else { $effectResult = '无效果记录'; } $rows[] = [ $usedAt, $petName, $skillName, $staminaCost, $effectResult ?: '-', $status ]; } catch (\Throwable $e) { // 如果出现异常,添加一个错误行 $usedAtDisplay = '未知'; if ($log->used_at) { try { if ($log->used_at instanceof \Carbon\Carbon) { $usedAtDisplay = $log->used_at->format('Y-m-d H:i:s'); } else { $usedAtDisplay = (string) $log->used_at; } } catch (\Exception $e) { $usedAtDisplay = '时间格式错误'; } } $rows[] = [ $usedAtDisplay, $log->pet ? $log->pet->name : '未知', $log->skill ? $log->skill->skill_name : '未知', '-', '数据解析错误', '错误' ]; } } $table = new Table($headers, $rows); $html = '
'; $html .= '
最近技能使用记录 (最近10次)
'; $html .= $table->render(); $html .= '
'; return $html; } /** * 神像buff信息卡片 * * @param int $userId 用户ID * @return Card */ protected function buffInfoCard($userId) { // 获取用户的神像buff信息 $buffs = FarmGodBuff::where('user_id', $userId) ->orderBy('expire_time', 'desc') ->get(); if ($buffs->isEmpty()) { return new Card('神像加持信息', new Alert('warning', '该用户没有神像加持信息')); } // 创建buff表格 $headers = [ '加持类型', '过期时间', '状态' ]; $rows = []; $buffTypeNames = [ 1 => '丰收之神', 2 => '雨露之神', 3 => '屠草之神', 4 => '拭虫之神', ]; foreach ($buffs as $buff) { try { $buffType = $buffTypeNames[$buff->buff_type] ?? "类型{$buff->buff_type}"; $isActive = now()->lt($buff->expire_time); $status = $isActive ? '生效中' : '已过期'; $rows[] = [ $buffType, $buff->expire_time, $status, ]; } catch (\Throwable) { // 如果出现异常,添加一个错误行 $rows[] = [ '数据错误', $buff->expire_time ?? '未知', '数据错误', ]; } } $table = new Table($headers, $rows); $content = $table->render(); return new Card('神像加持信息', $content); } /** * 用户列表网格 * * @return Grid */ protected function grid() { return Grid::make(User::with([ 'info', 'farmUser' ]), function (Grid $grid) { $grid->column('id', 'ID')->sortable(); // 用户基本信息 $grid->column('username', '用户名'); $grid->column('info.nickname', '昵称'); // 农场信息 $grid->column('farmUser.house_level', '房屋等级')->sortable(); // 土地统计 $grid->column('id', '土地统计')->display(function ($userId) { $lands = FarmLand::where('user_id', $userId)->get(); if ($lands->isEmpty()) { return '无土地'; } $landTypeStats = $lands->groupBy('land_type')->map->count(); $totalLands = $lands->count(); $html = "
总计: {$totalLands}块土地
"; $landTypeNames = [ 1 => '普通土地', 2 => '红土地', 3 => '黑土地', 4 => '金土地', 5 => '蓝土地', 6 => '紫土地', ]; foreach ($landTypeStats as $typeId => $count) { $typeName = $landTypeNames[$typeId] ?? "类型{$typeId}"; $html .= "
{$typeName}: {$count}块
"; } return $html; }); // 作物统计 $grid->column('id', '作物统计')->display(function ($userId) { $crops = FarmCrop::where('user_id', $userId)->count(); return $crops > 0 ? "{$crops}种作物" : '无作物'; }); // 物品统计 $grid->column('id', '物品统计')->display(function ($userId) { $itemCount = ItemUser::where('user_id', $userId)->count(); return $itemCount > 0 ? "{$itemCount}种物品" : '无物品'; }); // 代币统计 $grid->column('id', '代币统计')->display(function ($userId) { $fundCount = FundModel::where('user_id', $userId)->count(); return $fundCount > 0 ? "{$fundCount}个账户" : '无账户'; }); // 宠物统计 $grid->column('id', '宠物统计')->display(function ($userId) { $pets = PetUser::where('user_id', $userId)->get(); if ($pets->isEmpty()) { return '无宠物'; } $totalPets = $pets->count(); $maxLevel = $pets->max('level'); // 品阶功能已废弃,移除品阶统计 $html = "
总计: {$totalPets}只宠物
"; $html .= "
最高等级: {$maxLevel}
"; // 品阶功能已废弃,不再显示品阶分布 return $html; }); $grid->column('created_at', '创建时间')->sortable(); // 添加查看详情操作 $grid->actions(function (Grid\Displayers\Actions $actions) { // 禁用默认操作按钮 $actions->disableDelete(); $actions->disableEdit(); $actions->disableQuickEdit(); // 修改查看按钮,使其打开详情页 $actions->append('查看详情'); }); // 禁用创建按钮 $grid->disableCreateButton(); // 禁用批量操作 $grid->disableBatchActions(); // 添加搜索 $grid->filter(function (Grid\Filter $filter) { $filter->equal('id', '用户ID'); $filter->like('username', '用户名'); $filter->like('info.nickname', '昵称'); $filter->equal('farmUser.house_level', '房屋等级'); }); }); } /** * 获取果实信息 * * @param int $itemId 物品ID * @return string */ protected function getFruitInfo($itemId, $number) { try { // 查询物品信息 $item = \App\Module\GameItems\Models\Item::find($itemId); if ($item) { return " {$item->name} 数量 : {$number}
ID: {$itemId}"; } else { return "物品ID: {$itemId} , 数量 {$number}
物品不存在"; } } catch (\Exception $e) { return "获取失败
ID: {$itemId}"; } } /** * 获取种子可能的产出信息 * * @param \App\Module\Farm\Models\FarmSeed $seed 种子对象 * @return string */ protected function getSeedPossibleOutputs($seed) { try { $outputs = $seed->outputs; if ($outputs->isEmpty()) { return '无产出配置'; } $outputInfo = []; foreach ($outputs as $output) { try { $item = \App\Module\GameItems\Models\Item::find($output->item_id); $itemName = $item ? $item->name : "物品{$output->item_id}"; $probability = $output->probability ?? 0; $outputInfo[] = "{$itemName} ({$probability}%)"; } catch (\Exception $e) { $outputInfo[] = "物品{$output->item_id}"; } } return '可能产出:
' . implode('
', $outputInfo) . '
'; } catch (\Exception $e) { return '获取产出信息失败'; } } }