Pārlūkot izejas kodu

新增URS推广模块图表控制器

- 创建UrsPromotionMetricsController主控制器,提供URS推广数据统计页面
- 新增UrsNewUsersChart折线图组件,显示每日新用户数量趋势,支持7/14/28/90天时间范围选择
- 新增UrsActiveUsersCard数字卡片组件,显示当前活跃用户数量统计
- 新增UrsPromotionRankingCard排名组件,显示直推、间推、三推、团队推广用户数量排行榜前10名
- 在后台菜单中添加'URS推广数据统计'菜单项,路由为admin/urs-promotion/metrics
- 修复路由注解配置问题,确保路由正确注册和访问

功能特点:
- 新用户折线图支持多时间段查询,实时统计URS用户映射表数据
- 活跃用户卡片显示当前活跃状态用户总数
- 推广排名支持四个维度:直推、间推、三推、团队总数,各显示前10名用户
- 所有图表组件基于UCore图表框架,样式统一美观
- 页面布局采用6:6分栏,左侧显示趋势图表,右侧显示排名数据
AI Assistant 6 mēneši atpakaļ
vecāks
revīzija
27e33b949d

+ 160 - 0
AiWork/202506/221618-物品统计图表菜单配置完成.md

@@ -0,0 +1,160 @@
+# 物品统计图表菜单配置完成
+
+**时间**: 2025-06-22 16:18  
+**任务**: 加入菜单 - 为物品模块图表控制器添加后台菜单
+
+## 任务完成情况
+
+✅ **已完成** - 成功将物品统计图表功能添加到后台管理菜单中
+
+## 实现内容
+
+### 1. 菜单配置
+
+#### 菜单基本信息
+- **菜单ID**: 597
+- **父菜单ID**: 215 (游戏物品管理)
+- **菜单标题**: 物品统计图表
+- **菜单图标**: fa-bar-chart
+- **菜单URI**: game-items-metrics
+- **排序**: 34
+- **显示状态**: 1 (显示)
+
+#### 菜单层级结构
+```
+游戏系统设置 (ID: 259)
+└── 游戏物品管理 (ID: 215)
+    ├── 物品设置
+    ├── 物品组内容
+    ├── 合成配方管理
+    ├── 宝箱配置管理
+    └── 物品统计图表 ← 新添加
+```
+
+### 2. 数据库操作
+
+#### SQL执行记录
+```sql
+-- 查询最大order值
+SELECT MAX(`order`) as max_order FROM kku_admin_menu WHERE parent_id = 215;
+-- 结果: max_order = 33
+
+-- 添加菜单项
+INSERT INTO kku_admin_menu (parent_id, `order`, title, icon, uri, `show`, created_at, updated_at) 
+VALUES (215, 34, '物品统计图表', 'fa-bar-chart', 'game-items-metrics', 1, NOW(), NOW());
+
+-- 验证添加结果
+SELECT id, parent_id, title, icon, uri, `order`, `show` FROM kku_admin_menu WHERE title = '物品统计图表';
+```
+
+#### 菜单验证结果
+```json
+{
+  "id": 597,
+  "parent_id": 215,
+  "title": "物品统计图表",
+  "icon": "fa-bar-chart",
+  "uri": "game-items-metrics",
+  "order": 34,
+  "show": 1
+}
+```
+
+### 3. 功能验证
+
+#### 菜单显示测试
+✅ **菜单可见性**: 菜单在后台正确显示  
+✅ **菜单层级**: 正确显示在"游戏系统设置" -> "游戏物品管理"下  
+✅ **菜单排序**: 按order值正确排序,显示在最后位置  
+✅ **菜单图标**: fa-bar-chart图标正确显示  
+
+#### 菜单功能测试
+✅ **菜单点击**: 点击菜单可以正常跳转  
+✅ **页面访问**: 成功跳转到 `/admin/game-items-metrics`  
+✅ **页面加载**: 图表页面完整加载,显示四个图表  
+✅ **功能正常**: 所有图表功能正常工作  
+
+#### 访问路径验证
+- **完整路径**: 游戏系统设置 -> 游戏物品管理 -> 物品统计图表
+- **URL地址**: `http://kku_laravel.local.gd/admin/game-items-metrics`
+- **页面标题**: "物品统计图表 | Admin"
+
+### 4. 菜单设计考虑
+
+#### 位置选择理由
+- **归属模块**: 属于GameItems模块,放在"游戏物品管理"下合理
+- **功能性质**: 是配置类功能,放在"游戏系统设置"下合适
+- **用户体验**: 与其他物品管理功能集中,便于查找
+
+#### 图标选择
+- **fa-bar-chart**: 柱状图图标,直观表示统计图表功能
+- **语义明确**: 用户一眼就能识别这是图表相关功能
+- **风格统一**: 与其他菜单图标风格保持一致
+
+#### 排序位置
+- **order: 34**: 放在最后位置,不影响现有菜单顺序
+- **逻辑合理**: 统计图表作为分析工具,放在配置项之后合适
+
+### 5. 与现有菜单的关系
+
+#### 同级菜单对比
+| 菜单项 | Order | 功能类型 | 状态 |
+|--------|-------|----------|------|
+| 物品设置 | 27 | 基础配置 | 显示 |
+| 物品组内容 | 30 | 内容管理 | 显示 |
+| 合成配方管理 | 31 | 配置管理 | 显示 |
+| 宝箱配置管理 | 33 | 配置管理 | 显示 |
+| **物品统计图表** | **34** | **数据分析** | **显示** |
+
+#### 功能互补性
+- **基础配置** -> **内容管理** -> **数据分析**
+- 形成完整的物品管理工作流程
+- 统计图表为其他功能提供数据支持
+
+### 6. 用户使用流程
+
+#### 典型使用场景
+1. **管理员登录后台**
+2. **点击"游戏系统设置"**
+3. **展开"游戏物品管理"**
+4. **点击"物品统计图表"**
+5. **查看三大材料持有排名**
+6. **使用时间筛选功能分析数据**
+
+#### 便利性提升
+- **一键访问**: 从菜单直接访问,无需记忆URL
+- **逻辑分组**: 与相关功能放在一起,便于管理
+- **视觉识别**: 图标清晰,功能一目了然
+
+## 代码提交
+
+**提交信息**: 
+```
+物品模块:添加图表控制器到后台菜单
+
+- 在游戏系统设置->游戏物品管理下添加'物品统计图表'菜单项
+- 菜单ID: 597, 父菜单ID: 215, 排序: 34
+- 图标: fa-bar-chart, URI: game-items-metrics
+- 菜单路径: 游戏系统设置 -> 游戏物品管理 -> 物品统计图表
+- 功能: 提供三大材料持有排名的可视化统计分析
+```
+
+**提交哈希**: d7915926
+
+## 任务完成度
+
+✅ **菜单添加** - 成功添加到后台菜单系统  
+✅ **位置合理** - 放在合适的菜单层级下  
+✅ **功能可用** - 菜单点击后功能正常  
+✅ **用户体验** - 提供便捷的访问方式  
+
+## 后续建议
+
+1. **权限控制**: 可考虑为图表功能添加专门的权限控制
+2. **菜单优化**: 如果图表功能扩展,可考虑创建独立的"数据分析"菜单组
+3. **用户培训**: 可以在用户手册中说明图表功能的使用方法
+4. **性能监控**: 关注图表页面的加载性能,必要时添加缓存
+
+## 总结
+
+物品统计图表功能现在已经完全集成到后台管理系统中,管理员可以通过菜单便捷地访问三大材料的持有排名统计,大大提升了数据分析的便利性和用户体验!

+ 7 - 3
AiWork/now.md

@@ -1,8 +1,12 @@
 # 当前工作状态
 
-物品模块,增加图表控制器,参考 app/Module/Admin/AdminControllers/MetricsController.php
-三大材料(木材/石材/钢材)的持有排名,用户排名
-
+Urs推广模块,新增图表控制器,参考app/Module/Admin/AdminControllers/MetricsController.php
+新用户折线图,每日的新用户数量
+活跃用户数字 卡片
+推广用户数量(直推),排名
+推广用户数量(间推),排名
+推广用户数量(三推),排名
+推广用户数量(团队),排名
 
 ## 🎉 农贸市场图表分析页面报错修复完成 (2025-06-22 15:30)
 

+ 78 - 0
app/Module/UrsPromotion/AdminControllers/Metrics/UrsActiveUsersCard.php

@@ -0,0 +1,78 @@
+<?php
+
+namespace App\Module\UrsPromotion\AdminControllers\Metrics;
+
+use App\Module\UrsPromotion\Models\UrsUserMapping;
+use Dcat\Admin\Widgets\Metrics\Card;
+use Illuminate\Http\Request;
+
+/**
+ * URS活跃用户数字卡片
+ * 显示当前活跃用户数量
+ */
+class UrsActiveUsersCard extends Card
+{
+    /**
+     * 卡片高度
+     */
+    protected $height = 140;
+    
+    /**
+     * 卡片标题
+     */
+    protected $title = 'URS活跃用户';
+
+    /**
+     * 初始化卡片
+     */
+    public function __construct()
+    {
+        if ($options = $this->defaultChartOptions()) {
+            $this->chartOptions = $options;
+        }
+
+        $this->init();
+    }
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     * @return mixed|void
+     */
+    public function handle(Request $request)
+    {
+        $activeCount = $this->getActiveUsersCount();
+        $this->withContent($activeCount);
+    }
+
+    /**
+     * 获取活跃用户数量
+     *
+     * @return int
+     */
+    private function getActiveUsersCount(): int
+    {
+        return UrsUserMapping::where('status', UrsUserMapping::STATUS_VALID)
+            ->where('is_active', UrsUserMapping::ACTIVE_YES)
+            ->count();
+    }
+
+    /**
+     * 设置卡片内容
+     *
+     * @param int $content 活跃用户数量
+     * @return $this
+     */
+    public function withContent($content)
+    {
+        return $this->content(
+            <<<HTML
+<div class="d-flex flex-column flex-wrap text-center">
+    <h1 class="font-lg-2 mt-2 mb-0">{$content}</h1>
+    <small class="text-muted">当前活跃用户数</small>
+</div>
+HTML
+        );
+    }
+}

+ 111 - 0
app/Module/UrsPromotion/AdminControllers/Metrics/UrsNewUsersChart.php

@@ -0,0 +1,111 @@
+<?php
+
+namespace App\Module\UrsPromotion\AdminControllers\Metrics;
+
+use App\Module\UrsPromotion\Models\UrsUserMapping;
+use Carbon\Carbon;
+use Dcat\Admin\Widgets\Metrics\Line;
+use Illuminate\Http\Request;
+
+/**
+ * URS新用户折线图
+ * 显示每日新用户数量趋势
+ */
+class UrsNewUsersChart extends Line
+{
+    /**
+     * 初始化卡片内容
+     *
+     * @return void
+     */
+    protected function init()
+    {
+        parent::init();
+        
+        $this->height(300);
+        $this->chartHeight(180);
+        
+        $this->title('URS新用户趋势');
+        $this->dropdown([
+            '7'  => '最近 7 天',
+            '14' => '最近 14 天',
+            '28' => '最近 28 天',
+            '90' => '最近 90 天',
+        ]);
+    }
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     *
+     * @return mixed|void
+     */
+    public function handle(Request $request)
+    {
+        $days = (int) $request->get('option', 7);
+        $data = $this->getNewUsersData($days);
+        
+        // 卡片内容 - 显示总数
+        $this->withContent($data['total']);
+        
+        // 图表数据 - 显示每日数量
+        $this->withChart($data['daily']);
+    }
+
+    /**
+     * 获取新用户数据
+     *
+     * @param int $days 天数
+     * @return array
+     */
+    private function getNewUsersData(int $days): array
+    {
+        $endDate = Carbon::today();
+        $startDate = $endDate->copy()->subDays($days - 1);
+        
+        // 获取指定时间范围内的新用户数据
+        $newUsers = UrsUserMapping::where('created_at', '>=', $startDate)
+            ->where('created_at', '<=', $endDate->endOfDay())
+            ->where('status', UrsUserMapping::STATUS_VALID)
+            ->selectRaw('DATE(created_at) as date, COUNT(*) as count')
+            ->groupBy('date')
+            ->orderBy('date')
+            ->get()
+            ->keyBy('date');
+        
+        // 构建每日数据数组
+        $dailyData = [];
+        $totalCount = 0;
+        
+        for ($i = 0; $i < $days; $i++) {
+            $date = $startDate->copy()->addDays($i)->format('Y-m-d');
+            $count = $newUsers->get($date)->count ?? 0;
+            $dailyData[] = $count;
+            $totalCount += $count;
+        }
+        
+        return [
+            'total' => number_format($totalCount),
+            'daily' => $dailyData,
+        ];
+    }
+
+    /**
+     * 设置图表数据
+     *
+     * @param array $data
+     * @return $this
+     */
+    public function withChart(array $data)
+    {
+        return $this->chart([
+            'series' => [
+                [
+                    'name' => $this->title,
+                    'data' => $data,
+                ],
+            ],
+        ]);
+    }
+}

+ 239 - 0
app/Module/UrsPromotion/AdminControllers/Metrics/UrsPromotionRankingCard.php

@@ -0,0 +1,239 @@
+<?php
+
+namespace App\Module\UrsPromotion\AdminControllers\Metrics;
+
+use App\Module\UrsPromotion\Models\UrsUserMapping;
+use App\Module\User\Models\User;
+use Dcat\Admin\Widgets\Metrics\Card;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * URS推广用户排名卡片
+ * 显示直推、间推、三推、团队推广用户数量排名
+ */
+class UrsPromotionRankingCard extends Card
+{
+    /**
+     * 卡片高度
+     */
+    protected $height = 400;
+    
+    /**
+     * 卡片标题
+     */
+    protected $title = 'URS推广排行榜';
+
+    /**
+     * 初始化卡片
+     */
+    public function __construct()
+    {
+        if ($options = $this->defaultChartOptions()) {
+            $this->chartOptions = $options;
+        }
+
+        $this->init();
+    }
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     * @return mixed|void
+     */
+    public function handle(Request $request)
+    {
+        $rankings = $this->getPromotionRankings();
+        $this->withContent($rankings);
+    }
+
+    /**
+     * 获取推广排名数据
+     *
+     * @return array
+     */
+    private function getPromotionRankings(): array
+    {
+        // 获取直推排名前10
+        $directRanking = $this->getDirectRanking();
+        
+        // 获取间推排名前10
+        $indirectRanking = $this->getIndirectRanking();
+        
+        // 获取三推排名前10
+        $thirdRanking = $this->getThirdRanking();
+        
+        // 获取团队总数排名前10
+        $teamRanking = $this->getTeamRanking();
+
+        return [
+            'direct' => $directRanking,
+            'indirect' => $indirectRanking,
+            'third' => $thirdRanking,
+            'team' => $teamRanking,
+        ];
+    }
+
+    /**
+     * 获取直推排名
+     *
+     * @return array
+     */
+    private function getDirectRanking(): array
+    {
+        return UrsUserMapping::select([
+                'urs_promotion_user_mappings.urs_user_id',
+                'urs_promotion_user_mappings.user_id',
+                'urs_promotion_user_mappings.direct_count',
+                'users.nickname'
+            ])
+            ->leftJoin('users', 'urs_promotion_user_mappings.user_id', '=', 'users.id')
+            ->where('urs_promotion_user_mappings.status', UrsUserMapping::STATUS_VALID)
+            ->where('urs_promotion_user_mappings.direct_count', '>', 0)
+            ->orderBy('urs_promotion_user_mappings.direct_count', 'desc')
+            ->limit(10)
+            ->get()
+            ->toArray();
+    }
+
+    /**
+     * 获取间推排名
+     *
+     * @return array
+     */
+    private function getIndirectRanking(): array
+    {
+        return UrsUserMapping::select([
+                'urs_promotion_user_mappings.urs_user_id',
+                'urs_promotion_user_mappings.user_id',
+                'urs_promotion_user_mappings.indirect_count',
+                'users.nickname'
+            ])
+            ->leftJoin('users', 'urs_promotion_user_mappings.user_id', '=', 'users.id')
+            ->where('urs_promotion_user_mappings.status', UrsUserMapping::STATUS_VALID)
+            ->where('urs_promotion_user_mappings.indirect_count', '>', 0)
+            ->orderBy('urs_promotion_user_mappings.indirect_count', 'desc')
+            ->limit(10)
+            ->get()
+            ->toArray();
+    }
+
+    /**
+     * 获取三推排名
+     *
+     * @return array
+     */
+    private function getThirdRanking(): array
+    {
+        return UrsUserMapping::select([
+                'urs_promotion_user_mappings.urs_user_id',
+                'urs_promotion_user_mappings.user_id',
+                'urs_promotion_user_mappings.third_count',
+                'users.nickname'
+            ])
+            ->leftJoin('users', 'urs_promotion_user_mappings.user_id', '=', 'users.id')
+            ->where('urs_promotion_user_mappings.status', UrsUserMapping::STATUS_VALID)
+            ->where('urs_promotion_user_mappings.third_count', '>', 0)
+            ->orderBy('urs_promotion_user_mappings.third_count', 'desc')
+            ->limit(10)
+            ->get()
+            ->toArray();
+    }
+
+    /**
+     * 获取团队总数排名
+     *
+     * @return array
+     */
+    private function getTeamRanking(): array
+    {
+        return UrsUserMapping::select([
+                'urs_promotion_user_mappings.urs_user_id',
+                'urs_promotion_user_mappings.user_id',
+                'urs_promotion_user_mappings.promotion_count',
+                'users.nickname'
+            ])
+            ->leftJoin('users', 'urs_promotion_user_mappings.user_id', '=', 'users.id')
+            ->where('urs_promotion_user_mappings.status', UrsUserMapping::STATUS_VALID)
+            ->where('urs_promotion_user_mappings.promotion_count', '>', 0)
+            ->orderBy('urs_promotion_user_mappings.promotion_count', 'desc')
+            ->limit(10)
+            ->get()
+            ->toArray();
+    }
+
+    /**
+     * 设置卡片内容
+     *
+     * @param array $rankings 排名数据
+     * @return $this
+     */
+    public function withContent(array $rankings)
+    {
+        $directHtml = $this->buildRankingHtml($rankings['direct'], 'direct_count', '直推');
+        $indirectHtml = $this->buildRankingHtml($rankings['indirect'], 'indirect_count', '间推');
+        $thirdHtml = $this->buildRankingHtml($rankings['third'], 'third_count', '三推');
+        $teamHtml = $this->buildRankingHtml($rankings['team'], 'promotion_count', '团队');
+
+        return $this->content(
+            <<<HTML
+<div class="row">
+    <div class="col-6">
+        <h6 class="text-primary">直推排行榜</h6>
+        {$directHtml}
+    </div>
+    <div class="col-6">
+        <h6 class="text-success">间推排行榜</h6>
+        {$indirectHtml}
+    </div>
+</div>
+<div class="row mt-3">
+    <div class="col-6">
+        <h6 class="text-warning">三推排行榜</h6>
+        {$thirdHtml}
+    </div>
+    <div class="col-6">
+        <h6 class="text-info">团队排行榜</h6>
+        {$teamHtml}
+    </div>
+</div>
+HTML
+        );
+    }
+
+    /**
+     * 构建排名HTML
+     *
+     * @param array $data 排名数据
+     * @param string $countField 数量字段
+     * @param string $type 类型名称
+     * @return string
+     */
+    private function buildRankingHtml(array $data, string $countField, string $type): string
+    {
+        if (empty($data)) {
+            return '<small class="text-muted">暂无数据</small>';
+        }
+
+        $html = '<div class="ranking-list">';
+        foreach ($data as $index => $item) {
+            $rank = $index + 1;
+            $nickname = $item['nickname'] ?? 'URS用户' . $item['urs_user_id'];
+            $count = $item[$countField] ?? 0;
+            
+            $badgeClass = $rank <= 3 ? 'badge-warning' : 'badge-secondary';
+            
+            $html .= <<<HTML
+<div class="d-flex justify-content-between align-items-center mb-1">
+    <span class="badge {$badgeClass}">{$rank}</span>
+    <span class="text-truncate mx-2" style="max-width: 80px;" title="{$nickname}">{$nickname}</span>
+    <span class="font-weight-bold">{$count}</span>
+</div>
+HTML;
+        }
+        $html .= '</div>';
+
+        return $html;
+    }
+}

+ 43 - 0
app/Module/UrsPromotion/AdminControllers/UrsPromotionMetricsController.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Module\UrsPromotion\AdminControllers;
+
+use Dcat\Admin\Layout\Column;
+use Dcat\Admin\Layout\Content;
+use Dcat\Admin\Layout\Row;
+use Spatie\RouteAttributes\Attributes\Get;
+use UCore\DcatAdmin\AdminController;
+
+/**
+ * URS推广模块图表控制器
+ * 
+ * @route /admin/urs-promotion/metrics
+ */
+class UrsPromotionMetricsController extends AdminController
+{
+    /**
+     * 图表首页
+     * 显示URS推广模块的各种统计图表
+     */
+    #[Get('urs-promotion/metrics')]
+    public function index(Content $content)
+    {
+        return $content
+            ->header('URS推广数据统计')
+            ->description('URS推广模块数据统计图表')
+            ->body(function (Row $row) {
+                $row->column(6, function (Column $column) {
+                    // 新用户折线图 - 显示每日新用户数量趋势
+                    $column->row(new \App\Module\UrsPromotion\AdminControllers\Metrics\UrsNewUsersChart());
+
+                    // 活跃用户数字卡片 - 显示当前活跃用户数量
+                    $column->row(new \App\Module\UrsPromotion\AdminControllers\Metrics\UrsActiveUsersCard());
+                });
+
+                $row->column(6, function (Column $column) {
+                    // 推广用户排名 - 显示各级推广用户数量排名
+                    $column->row(new \App\Module\UrsPromotion\AdminControllers\Metrics\UrsPromotionRankingCard());
+                });
+            });
+    }
+}