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.show')]
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 redirect()->route('dcat.admin.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 .= "| {$typeName} | {$count} |
";
}
$statsContent .= '
';
// 土地状态统计
$statsContent .= '
';
$statsContent .= '
土地状态统计
';
$statsContent .= '
';
$statsContent .= '| 土地状态 | 数量 |
';
$statsContent .= '';
$landStatusNames = [
0 => '空闲',
1 => '种植中',
2 => '灾害',
3 => '可收获',
4 => '枯萎',
];
foreach ($landStatusStats as $statusId => $count) {
$statusName = $landStatusNames[$statusId] ?? "状态{$statusId}";
$statsContent .= "| {$statusName} | {$count} |
";
}
$statsContent .= '
';
// 灾害统计
$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 .= "| {$typeName} | {$count} | {$penalty} |
";
}
// 添加总计行
$totalPenalty = $totalDisasters > 0 ? ($totalDisasters * 5) . '%' : '0%';
$statsContent .= "| 总计 | {$totalDisasters} | {$totalPenalty} |
";
$statsContent .= '
';
$statsContent .= '
';
// 创建土地详情表格
$headers = [
'ID', '位置', '土地类型', '状态', '种植作物', '种植时间', '生长阶段', '本阶段开始时间', '本阶段结束时间(剩余)',
'果实信息', '灾害情况'
];
$rows = [];
foreach ($lands as $land) {
$landType = $land->landType ? $land->landType->name : "类型{$land->land_type}";
$status = $landStatusNames[$land->status] ?? "状态{$land->status}";
$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);
} 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('grade', 'desc')
->get();
if ($pets->isEmpty()) {
return new Card('宠物信息', new Alert('warning', '该用户没有宠物信息'));
}
// 宠物统计
$totalPets = $pets->count();
$gradeStats = $pets->groupBy('grade')->map->count();
$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 = [
1 => '一品',
2 => '二品',
3 => '三品',
4 => '四品',
];
$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 = $gradeNames[$pet->grade] ?? "品阶{$pet->grade}";
$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,
$gradeName,
$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 (!$gradeStats->isEmpty()) {
$statsHtml .= '品阶分布: ';
foreach ($gradeStats as $grade => $count) {
$gradeName = $gradeNames[$grade] ?? "品阶{$grade}";
$statsHtml .= "{$gradeName}: {$count}只 ";
}
$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');
$gradeStats = $pets->groupBy('grade')->map->count();
$html = "总计: {$totalPets}只宠物
";
$html .= "最高等级: {$maxLevel}
";
// 显示品阶分布
$gradeNames = [1 => '一品', 2 => '二品', 3 => '三品', 4 => '四品'];
foreach ($gradeStats as $grade => $count) {
$gradeName = $gradeNames[$grade] ?? "品阶{$grade}";
$html .= "{$gradeName}: {$count}只
";
}
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)
{
try {
// 查询物品信息
$item = \App\Module\GameItems\Models\Item::find($itemId);
if ($item) {
return "{$item->name}
ID: {$itemId}";
} else {
return "物品ID: {$itemId}
物品不存在";
}
} 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 '获取产出信息失败';
}
}
}