|
|
@@ -14,6 +14,9 @@ use App\Module\Fund\Models\FundModel;
|
|
|
use App\Module\Fund\Services\AccountService;
|
|
|
use App\Module\GameItems\Enums\ITEM_TYPE;
|
|
|
use App\Module\GameItems\Models\ItemUser;
|
|
|
+use App\Module\Pet\Models\PetUser;
|
|
|
+use App\Module\Pet\Models\PetActiveSkill;
|
|
|
+use App\Module\Pet\Enums\PetStatus;
|
|
|
use App\Module\User\Models\User;
|
|
|
use Dcat\Admin\Grid;
|
|
|
use Dcat\Admin\Layout\Content;
|
|
|
@@ -108,7 +111,13 @@ class FarmUserSummaryController extends AdminController
|
|
|
// 第四行:代币信息
|
|
|
$row->column(12, $this->fundInfoCard($user->id));
|
|
|
|
|
|
- // 第五行:神像buff信息
|
|
|
+ // 第五行:宠物信息
|
|
|
+ $row->column(12, $this->petInfoCard($user->id));
|
|
|
+
|
|
|
+ // 第六行:宠物生活技能情况
|
|
|
+ $row->column(12, $this->petLifeSkillsCard($user->id));
|
|
|
+
|
|
|
+ // 第七行:神像buff信息
|
|
|
$row->column(12, $this->buffInfoCard($user->id));
|
|
|
});
|
|
|
}
|
|
|
@@ -673,6 +682,284 @@ class FarmUserSummaryController extends AdminController
|
|
|
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 = ['宠物名称', '品阶', '等级', '经验', '体力', '状态', '创建时间'];
|
|
|
+ $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 => '<span class="badge badge-success">' . $statusName . '</span>',
|
|
|
+ PetStatus::FIGHTING => '<span class="badge badge-warning">' . $statusName . '</span>',
|
|
|
+ PetStatus::DEAD => '<span class="badge badge-danger">' . $statusName . '</span>',
|
|
|
+ PetStatus::FEEDING, PetStatus::TRAINING => '<span class="badge badge-info">' . $statusName . '</span>',
|
|
|
+ PetStatus::RESTING, PetStatus::TRAVELING => '<span class="badge badge-primary">' . $statusName . '</span>',
|
|
|
+ default => '<span class="badge badge-secondary">' . $statusName . '</span>',
|
|
|
+ };
|
|
|
+
|
|
|
+ $rows[] = [
|
|
|
+ $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,
|
|
|
+ '<span class="badge badge-danger">数据错误</span>',
|
|
|
+ $pet->created_at ? $pet->created_at->format('Y-m-d H:i:s') : '未知',
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $table = new Table($headers, $rows);
|
|
|
+
|
|
|
+ // 统计信息
|
|
|
+ $statsHtml = '<div class="row mb-3">';
|
|
|
+ $statsHtml .= '<div class="col-md-3"><strong>宠物总数:</strong> ' . $totalPets . '</div>';
|
|
|
+ $statsHtml .= '<div class="col-md-3"><strong>最高等级:</strong> ' . $levelStats['max_level'] . '</div>';
|
|
|
+ $statsHtml .= '<div class="col-md-3"><strong>平均等级:</strong> ' . $levelStats['avg_level'] . '</div>';
|
|
|
+ $statsHtml .= '<div class="col-md-3"><strong>总经验:</strong> ' . number_format($levelStats['total_exp']) . '</div>';
|
|
|
+ $statsHtml .= '</div>';
|
|
|
+
|
|
|
+ // 品阶统计
|
|
|
+ if (!$gradeStats->isEmpty()) {
|
|
|
+ $statsHtml .= '<div class="row mb-3"><div class="col-md-12"><strong>品阶分布:</strong> ';
|
|
|
+ foreach ($gradeStats as $grade => $count) {
|
|
|
+ $gradeName = $gradeNames[$grade] ?? "品阶{$grade}";
|
|
|
+ $statsHtml .= "{$gradeName}: {$count}只 ";
|
|
|
+ }
|
|
|
+ $statsHtml .= '</div></div>';
|
|
|
+ }
|
|
|
+
|
|
|
+ // 状态统计
|
|
|
+ if (!$statusStats->isEmpty()) {
|
|
|
+ $statsHtml .= '<div class="row mb-3"><div class="col-md-12"><strong>状态分布:</strong> ';
|
|
|
+ foreach ($statusStats as $status => $count) {
|
|
|
+ $statusName = $statusNames[$status] ?? "状态{$status}";
|
|
|
+ $statsHtml .= "{$statusName}: {$count}只 ";
|
|
|
+ }
|
|
|
+ $statsHtml .= '</div></div>';
|
|
|
+ }
|
|
|
+
|
|
|
+ $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 = '<div class="row mb-3">';
|
|
|
+ $statsHtml .= '<div class="col-md-3"><strong>总技能使用次数:</strong> ' . $totalSkills . '</div>';
|
|
|
+ $statsHtml .= '<div class="col-md-3"><strong>当前激活:</strong> <span class="badge badge-success">' . $activeCount . '</span></div>';
|
|
|
+ $statsHtml .= '<div class="col-md-3"><strong>已过期:</strong> <span class="badge badge-secondary">' . $expiredCount . '</span></div>';
|
|
|
+ $statsHtml .= '<div class="col-md-3"><strong>已取消:</strong> <span class="badge badge-warning">' . $cancelledCount . '</span></div>';
|
|
|
+ $statsHtml .= '</div>';
|
|
|
+
|
|
|
+ // 技能类型统计
|
|
|
+ if (!$skillTypeStats->isEmpty()) {
|
|
|
+ $statsHtml .= '<div class="row mb-3"><div class="col-md-12"><strong>技能使用统计:</strong> ';
|
|
|
+ foreach ($skillTypeStats as $skillName => $count) {
|
|
|
+ $statsHtml .= "<span class='badge badge-info mr-2'>{$skillName}: {$count}次</span> ";
|
|
|
+ }
|
|
|
+ $statsHtml .= '</div></div>';
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($activeSkills->isEmpty()) {
|
|
|
+ $content = $statsHtml . '<div class="alert alert-info">该用户的宠物还没有使用过生活技能</div>';
|
|
|
+ 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');
|
|
|
+
|
|
|
+ // 状态显示
|
|
|
+ $statusBadge = match($activeSkill->status) {
|
|
|
+ 'active' => '<span class="badge badge-success">生效中</span>',
|
|
|
+ 'expired' => '<span class="badge badge-secondary">已过期</span>',
|
|
|
+ 'cancelled' => '<span class="badge badge-warning">已取消</span>',
|
|
|
+ default => '<span class="badge badge-dark">' . $activeSkill->status . '</span>',
|
|
|
+ };
|
|
|
+
|
|
|
+ // 剩余时间
|
|
|
+ $remainingTime = '';
|
|
|
+ if ($activeSkill->status === 'active') {
|
|
|
+ $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 = '<span class="text-danger">已过期</span>';
|
|
|
+ }
|
|
|
+ } 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('<br>', $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') : '未知',
|
|
|
+ '<span class="badge badge-danger">数据错误</span>',
|
|
|
+ '-',
|
|
|
+ '数据解析错误'
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $table = new Table($headers, $rows);
|
|
|
+
|
|
|
+ $content = $statsHtml . $table->render();
|
|
|
+
|
|
|
+ // 添加说明信息
|
|
|
+ $content .= '<div class="alert alert-info mt-3">';
|
|
|
+ $content .= '<strong>说明:</strong><br>';
|
|
|
+ $content .= '• <strong>自动收菜</strong>:每分钟自动收获成熟的作物<br>';
|
|
|
+ $content .= '• <strong>自动播种</strong>:每分钟自动在空闲土地上播种<br>';
|
|
|
+ $content .= '• <strong>灾害防护</strong>:每5分钟检查并自动清除作物灾害<br>';
|
|
|
+ $content .= '• 所有自动操作仍需消耗相应的道具(种子、化肥等)';
|
|
|
+ $content .= '</div>';
|
|
|
+
|
|
|
+ return new Card('宠物生活技能情况', $content);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 神像buff信息卡片
|
|
|
*
|
|
|
@@ -796,6 +1083,30 @@ class FarmUserSummaryController extends AdminController
|
|
|
return $fundCount > 0 ? "{$fundCount}个账户" : '<span class="text-muted">无账户</span>';
|
|
|
});
|
|
|
|
|
|
+ // 宠物统计
|
|
|
+ $grid->column('id', '宠物统计')->display(function ($userId) {
|
|
|
+ $pets = PetUser::where('user_id', $userId)->get();
|
|
|
+ if ($pets->isEmpty()) {
|
|
|
+ return '<span class="text-muted">无宠物</span>';
|
|
|
+ }
|
|
|
+
|
|
|
+ $totalPets = $pets->count();
|
|
|
+ $maxLevel = $pets->max('level');
|
|
|
+ $gradeStats = $pets->groupBy('grade')->map->count();
|
|
|
+
|
|
|
+ $html = "<div>总计: {$totalPets}只宠物</div>";
|
|
|
+ $html .= "<div>最高等级: {$maxLevel}</div>";
|
|
|
+
|
|
|
+ // 显示品阶分布
|
|
|
+ $gradeNames = [1 => '一品', 2 => '二品', 3 => '三品', 4 => '四品'];
|
|
|
+ foreach ($gradeStats as $grade => $count) {
|
|
|
+ $gradeName = $gradeNames[$grade] ?? "品阶{$grade}";
|
|
|
+ $html .= "<div>{$gradeName}: {$count}只</div>";
|
|
|
+ }
|
|
|
+
|
|
|
+ return $html;
|
|
|
+ });
|
|
|
+
|
|
|
$grid->column('created_at', '创建时间')->sortable();
|
|
|
|
|
|
// 添加查看详情操作
|