column('id', 'ID')->sortable(); $grid->column('user.username', '用户名'); $grid->column('user_id', '用户ID'); $grid->column('message', '日志消息') ->limit(50) ->help('用户操作的详细描述'); $grid->column('source_type', '来源类型') ->display(function ($value) { if (!$value) { return '未知'; } // 处理枚举实例或字符串 $typeValue = $value instanceof REWARD_SOURCE_TYPE ? $value->value : $value; // 使用枚举获取名称和信息 if (REWARD_SOURCE_TYPE::isValid($typeValue)) { $info = REWARD_SOURCE_TYPE::getTypeInfo($typeValue); $name = $info['name']; $icon = $info['icon']; $category = $info['category']; // 根据分类设置标签颜色 $labelColors = [ 'gameplay' => 'primary', 'event' => 'warning', 'daily' => 'info', 'achievement' => 'success', 'progression' => 'success', 'farm' => 'warning', 'social' => 'info', 'shop' => 'primary', 'promotion' => 'danger', 'competition' => 'success', 'special' => 'warning', 'system' => 'default', 'unknown' => 'default' ]; $color = $labelColors[$category] ?? 'default'; return "{$icon} {$name}"; } return "{$value}"; }); $grid->column('source_id', '来源ID'); $grid->column('source_table', '来源表名') ->limit(20) ->display(function ($value) { // 使用原始的、未截断的值 $originalValue = $this->source_table; if (!$originalValue || !$this->source_id) { return $value; } // 获取对应的后台管理页面URL $url = self::getSourceDetailUrl($originalValue, $this->source_id); if ($url) { return "" . " {$value}"; } return $value; }); $grid->column('original_time', '原始时间') ->display(function ($value) { return $value ? $value->format('Y-m-d H:i:s') : '-'; }) ->sortable() ->help('业务发生的原始时间'); $grid->column('created_at', '收集时间') ->display(function ($value) { return $value ? $value->format('Y-m-d H:i:s') : '-'; }) ->sortable() ->help('日志收集时间'); // 筛选器 $grid->filter(function (Grid\Filter $filter) { $filter->equal('user_id', '用户ID'); $filter->like('message', '日志消息'); // 使用枚举生成来源类型选项 $sourceTypeOptions = []; foreach (REWARD_SOURCE_TYPE::cases() as $case) { $info = REWARD_SOURCE_TYPE::getTypeInfo($case->value); $sourceTypeOptions[$case->value] = $info['icon'] . ' ' . $info['name']; } $filter->equal('source_type', '来源类型') ->select($sourceTypeOptions); $filter->between('original_time', '原始时间')->datetime(); }); // 默认排序 - 按原始日志创建时间排序 $grid->model()->orderBy('original_time', 'desc'); // 禁用创建按钮 $grid->disableCreateButton(); // 禁用编辑 $grid->disableEditButton(); // 批量操作 $grid->batchActions(function (Grid\Tools\BatchActions $batch) { // 暂时注释掉批量删除功能,避免误删重要日志 // $batch->add('清理选中日志', new \App\Module\Game\AdminControllers\Actions\BatchDeleteUserLogsAction()); }); // 工具栏 $grid->tools(function (Grid\Tools $tools) { // 暂时注释掉工具按钮,避免类不存在错误 // $tools->append(new \App\Module\Game\AdminControllers\Tools\CleanExpiredLogsButton()); // $tools->append(new \App\Module\Game\AdminControllers\Tools\UserLogStatsButton()); }); }); } /** * Make a show builder. * * @param mixed $id * @return Show */ protected function detail($id) { return Show::make($id, UserLog::with(['user']), function (Show $show) { $show->field('id', 'ID'); $show->field('user.username', '用户名'); $show->field('user_id', '用户ID'); $show->field('message', '日志消息') ->unescape(); $show->field('source_type', '来源类型') ->as(function ($value) { if (!$value) { return '未知'; } // 处理枚举实例或字符串 $typeValue = $value instanceof REWARD_SOURCE_TYPE ? $value->value : $value; if (REWARD_SOURCE_TYPE::isValid($typeValue)) { $info = REWARD_SOURCE_TYPE::getTypeInfo($typeValue); return $info['icon'] . ' ' . $info['name'] . ' (' . $info['description'] . ')'; } return $value; }); $show->field('source_id', '来源ID'); $show->field('source_table', '来源表名'); $show->field('original_time', '原始时间') ->help('业务发生的原始时间'); $show->field('created_at', '收集时间') ->help('日志收集时间'); // 禁用编辑和删除按钮 $show->disableEditButton(); $show->disableDeleteButton(); }); } /** * Make a form builder. * * @return Form */ protected function form() { return Form::make(UserLog::class, function (Form $form) { $form->display('id', 'ID'); $form->number('user_id', '用户ID') ->required() ->help('关联的用户ID'); $form->textarea('message', '日志消息') ->required() ->rows(3) ->help('用户操作的详细描述'); // 使用枚举生成来源类型选项 $sourceTypeOptions = []; foreach (REWARD_SOURCE_TYPE::cases() as $case) { $info = REWARD_SOURCE_TYPE::getTypeInfo($case->value); $sourceTypeOptions[$case->value] = $info['icon'] . ' ' . $info['name']; } $form->select('source_type', '来源类型') ->options($sourceTypeOptions) ->help('日志来源的模块类型,使用标准化的奖励来源枚举'); $form->number('source_id', '来源ID') ->help('关联的业务记录ID'); $form->text('source_table', '来源表名') ->help('关联的数据库表名'); $form->display('created_at', '创建时间'); // 禁用删除按钮 $form->disableDeleteButton(); }); } /** * 获取来源详情页面URL * * @param string $sourceTable 来源表名 * @param int $sourceId 来源记录ID * @return string|null 详情页面URL,null表示无对应页面 */ public static function getSourceDetailUrl(string $sourceTable, int $sourceId): ?string { // 来源表名到后台路由的映射关系 $tableRouteMap = [ 'fund_logs' => 'fund-logs', 'item_transaction_logs' => 'game-items-transaction-logs', 'farm_harvest_logs' => 'farm-harvest-logs', 'farm_upgrade_logs' => 'farm-upgrade-logs', 'pet_battle_logs' => 'pet-battle-logs', 'pet_skill_logs' => 'pet-skill-logs', 'task_reward_logs' => 'task-reward-logs', 'task_reset_logs' => 'task-reset-logs', 'game_items_dismantle_logs' => 'game-items-dismantle-logs', 'system_logs' => 'system-logs', ]; // 检查是否有对应的路由 if (!isset($tableRouteMap[$sourceTable])) { return null; } $route = $tableRouteMap[$sourceTable]; // 生成详情页面URL return admin_url("{$route}/{$sourceId}"); } /** * 清理过期日志 * * @return \Illuminate\Http\JsonResponse */ public function cleanExpiredLogs() { try { $days = request('days', 30); $deletedCount = UserLogService::cleanExpiredLogs($days); return response()->json([ 'status' => true, 'message' => "成功清理 {$deletedCount} 条过期日志", ]); } catch (\Exception $e) { return response()->json([ 'status' => false, 'message' => '清理过期日志失败:' . $e->getMessage(), ]); } } /** * 获取用户日志统计信息 * * @return \Illuminate\Http\JsonResponse */ public function getStats() { try { $userId = request('user_id'); if (!$userId) { return response()->json([ 'status' => false, 'message' => '请提供用户ID', ]); } $stats = UserLogService::getUserLogStats($userId); return response()->json([ 'status' => true, 'data' => $stats, ]); } catch (\Exception $e) { return response()->json([ 'status' => false, 'message' => '获取统计信息失败:' . $e->getMessage(), ]); } } }