Просмотр исходного кода

feat(activity): 添加活动管理相关功能

- 新增活动配置、活动条件、活动参与记录和用户活动数据控制器
- 实现活动复制、开始、结束和关闭功能- 添加活动参与记录的标记完成、标记已领取和标记已过期功能
- 新增清理过期活动命令
Your Name 8 месяцев назад
Родитель
Сommit
f3d265859a
47 измененных файлов с 5887 добавлено и 0 удалено
  1. 119 0
      app/Module/Activity/AdminControllers/ActivityConditionController.php
  2. 337 0
      app/Module/Activity/AdminControllers/ActivityController.php
  3. 279 0
      app/Module/Activity/AdminControllers/ActivityParticipationController.php
  4. 123 0
      app/Module/Activity/AdminControllers/UserActivityDataController.php
  5. 139 0
      app/Module/Activity/Commands/CleanExpiredActivitiesCommand.php
  6. 219 0
      app/Module/Activity/Commands/GenerateActivityReportCommand.php
  7. 110 0
      app/Module/Activity/Commands/UpdateActivityStatusCommand.php
  8. 123 0
      app/Module/Activity/Docs/DEV.md
  9. 107 0
      app/Module/Activity/Dtos/ActivityConditionDto.php
  10. 191 0
      app/Module/Activity/Dtos/ActivityConfigDto.php
  11. 128 0
      app/Module/Activity/Dtos/ActivityParticipationDto.php
  12. 93 0
      app/Module/Activity/Dtos/ActivityRewardDto.php
  13. 90 0
      app/Module/Activity/Dtos/UserActivityDataDto.php
  14. 66 0
      app/Module/Activity/Enums/ACTIVITY_STATUS.php
  15. 72 0
      app/Module/Activity/Enums/ACTIVITY_TYPE.php
  16. 78 0
      app/Module/Activity/Enums/CONDITION_TYPE.php
  17. 60 0
      app/Module/Activity/Enums/PARTICIPATION_STATUS.php
  18. 60 0
      app/Module/Activity/Enums/REWARD_STATUS.php
  19. 41 0
      app/Module/Activity/Events/ActivityCompletedEvent.php
  20. 42 0
      app/Module/Activity/Events/ActivityCreatedEvent.php
  21. 59 0
      app/Module/Activity/Events/ActivityProgressUpdatedEvent.php
  22. 50 0
      app/Module/Activity/Events/ActivityRewardClaimedEvent.php
  23. 50 0
      app/Module/Activity/Events/ActivityStatusChangedEvent.php
  24. 41 0
      app/Module/Activity/Events/UserParticipatedEvent.php
  25. 63 0
      app/Module/Activity/Listeners/ActivityCompletedListener.php
  26. 61 0
      app/Module/Activity/Listeners/ActivityProgressListener.php
  27. 91 0
      app/Module/Activity/Listeners/ActivityStatusChangeListener.php
  28. 68 0
      app/Module/Activity/Listeners/RewardDistributionListener.php
  29. 63 0
      app/Module/Activity/Listeners/UserParticipationListener.php
  30. 421 0
      app/Module/Activity/Logics/ActivityLogic.php
  31. 333 0
      app/Module/Activity/Logics/ConditionLogic.php
  32. 193 0
      app/Module/Activity/Logics/ParticipationLogic.php
  33. 163 0
      app/Module/Activity/Logics/ProgressLogic.php
  34. 219 0
      app/Module/Activity/Logics/RewardLogic.php
  35. 103 0
      app/Module/Activity/Models/ActivityCondition.php
  36. 157 0
      app/Module/Activity/Models/ActivityConfig.php
  37. 154 0
      app/Module/Activity/Models/ActivityParticipation.php
  38. 111 0
      app/Module/Activity/Models/UserActivityData.php
  39. 95 0
      app/Module/Activity/Providers/ActivityServiceProvider.php
  40. 22 0
      app/Module/Activity/Repositorys/ActivityConditionRepository.php
  41. 22 0
      app/Module/Activity/Repositorys/ActivityConfigRepository.php
  42. 22 0
      app/Module/Activity/Repositorys/ActivityParticipationRepository.php
  43. 22 0
      app/Module/Activity/Repositorys/UserActivityDataRepository.php
  44. 373 0
      app/Module/Activity/Services/ActivityManagementService.php
  45. 320 0
      app/Module/Activity/Services/ActivityService.php
  46. 131 0
      app/Module/Activity/Services/RewardService.php
  47. 3 0
      noai.md

+ 119 - 0
app/Module/Activity/AdminControllers/ActivityConditionController.php

@@ -0,0 +1,119 @@
+<?php
+
+namespace App\Module\Activity\AdminControllers;
+
+use App\Module\Activity\Enums\CONDITION_TYPE;
+use App\Module\Activity\Models\ActivityConfig;
+use App\Module\Activity\Repositorys\ActivityConditionRepository;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+
+/**
+ * 活动条件控制器
+ */
+class ActivityConditionController extends AdminController
+{
+    /**
+     * 标题
+     *
+     * @return string
+     */
+    protected function title()
+    {
+        return '活动条件';
+    }
+
+    /**
+     * 创建表格
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(new ActivityConditionRepository(), function (Grid $grid) {
+            $grid->column('id', 'ID')->sortable();
+            $grid->column('activity_id', '活动')->display(function ($activityId) {
+                $activity = ActivityConfig::find($activityId);
+                return $activity ? $activity->name : "未知活动({$activityId})";
+            });
+            $grid->column('condition_type', '条件类型')->display(function ($type) {
+                return CONDITION_TYPE::getName($type);
+            });
+            $grid->column('is_participation_condition', '参与条件')->switch();
+            $grid->column('is_completion_condition', '完成条件')->switch();
+            $grid->column('display_order', '显示顺序');
+            $grid->column('created_at', '创建时间');
+            $grid->column('updated_at', '更新时间');
+
+            $grid->filter(function (Grid\Filter $filter) {
+                $filter->equal('id', 'ID');
+                $filter->equal('activity_id', '活动')->select(
+                    ActivityConfig::pluck('name', 'id')
+                );
+                $filter->equal('condition_type', '条件类型')->select(CONDITION_TYPE::getAll());
+                $filter->equal('is_participation_condition', '参与条件')->select([0 => '否', 1 => '是']);
+                $filter->equal('is_completion_condition', '完成条件')->select([0 => '否', 1 => '是']);
+            });
+        });
+    }
+
+    /**
+     * 创建详情页
+     *
+     * @param mixed $id
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new ActivityConditionRepository(), function (Show $show) {
+            $show->field('id', 'ID');
+            $show->field('activity_id', '活动')->as(function ($activityId) {
+                $activity = ActivityConfig::find($activityId);
+                return $activity ? $activity->name : "未知活动({$activityId})";
+            });
+            $show->field('condition_type', '条件类型')->as(function ($type) {
+                return CONDITION_TYPE::getName($type);
+            });
+            $show->field('condition_params', '条件参数')->json();
+            $show->field('is_participation_condition', '参与条件')->as(function ($value) {
+                return $value ? '是' : '否';
+            });
+            $show->field('is_completion_condition', '完成条件')->as(function ($value) {
+                return $value ? '是' : '否';
+            });
+            $show->field('display_order', '显示顺序');
+            $show->field('created_at', '创建时间');
+            $show->field('updated_at', '更新时间');
+        });
+    }
+
+    /**
+     * 创建表单
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new ActivityConditionRepository(), function (Form $form) {
+            $form->display('id', 'ID');
+            $form->select('activity_id', '活动')
+                ->options(ActivityConfig::pluck('name', 'id'))
+                ->required();
+            $form->select('condition_type', '条件类型')
+                ->options(CONDITION_TYPE::getAll())
+                ->required();
+            $form->textarea('condition_params', '条件参数')
+                ->help('JSON格式,根据条件类型填写不同的参数');
+            $form->switch('is_participation_condition', '参与条件')
+                ->default(false);
+            $form->switch('is_completion_condition', '完成条件')
+                ->default(false);
+            $form->number('display_order', '显示顺序')
+                ->default(0);
+            $form->display('created_at', '创建时间');
+            $form->display('updated_at', '更新时间');
+        });
+    }
+}

+ 337 - 0
app/Module/Activity/AdminControllers/ActivityController.php

@@ -0,0 +1,337 @@
+<?php
+
+namespace App\Module\Activity\AdminControllers;
+
+use App\Module\Activity\Enums\ACTIVITY_STATUS;
+use App\Module\Activity\Enums\ACTIVITY_TYPE;
+use App\Module\Activity\Models\ActivityConfig;
+use App\Module\Activity\Repositorys\ActivityConfigRepository;
+use App\Module\Game\Services\RewardService;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Layout\Content;
+use Dcat\Admin\Widgets\Card;
+use Dcat\Admin\Widgets\Table;
+
+/**
+ * 活动管理控制器
+ */
+class ActivityController extends AdminController
+{
+    /**
+     * 标题
+     *
+     * @return string
+     */
+    protected function title()
+    {
+        return '活动管理';
+    }
+
+    /**
+     * 创建表格
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(new ActivityConfigRepository(), function (Grid $grid) {
+            $grid->column('id', 'ID')->sortable();
+            $grid->column('name', '活动名称');
+            $grid->column('type', '活动类型')->display(function ($type) {
+                return ACTIVITY_TYPE::getName($type);
+            });
+            $grid->column('start_time', '开始时间')->sortable();
+            $grid->column('end_time', '结束时间')->sortable();
+            $grid->column('status', '状态')->display(function ($status) {
+                return ACTIVITY_STATUS::getName($status);
+            })->label([
+                ACTIVITY_STATUS::NOT_STARTED => 'default',
+                ACTIVITY_STATUS::IN_PROGRESS => 'success',
+                ACTIVITY_STATUS::ENDED => 'warning',
+                ACTIVITY_STATUS::CLOSED => 'danger',
+            ]);
+            $grid->column('display_order', '显示顺序')->sortable();
+            $grid->column('reward_group_id', '奖励组ID');
+            $grid->column('reward_group_code', '奖励组编码');
+            $grid->column('created_at', '创建时间');
+            $grid->column('updated_at', '更新时间');
+
+            $grid->filter(function (Grid\Filter $filter) {
+                $filter->equal('id', 'ID');
+                $filter->like('name', '活动名称');
+                $filter->equal('type', '活动类型')->select(ACTIVITY_TYPE::getAll());
+                $filter->equal('status', '状态')->select(ACTIVITY_STATUS::getAll());
+                $filter->between('start_time', '开始时间')->datetime();
+                $filter->between('end_time', '结束时间')->datetime();
+            });
+
+            $grid->actions(function (Grid\Displayers\Actions $actions) {
+                // 添加复制按钮
+                $actions->append('<a href="' . admin_url('activity/activities/' . $actions->getKey() . '/duplicate') . '"><i class="fa fa-copy"></i> 复制</a>');
+                
+                // 添加更新状态按钮
+                if ($actions->row->status === ACTIVITY_STATUS::NOT_STARTED) {
+                    $actions->append('<a href="' . admin_url('activity/activities/' . $actions->getKey() . '/start') . '"><i class="fa fa-play"></i> 开始</a>');
+                } elseif ($actions->row->status === ACTIVITY_STATUS::IN_PROGRESS) {
+                    $actions->append('<a href="' . admin_url('activity/activities/' . $actions->getKey() . '/end') . '"><i class="fa fa-stop"></i> 结束</a>');
+                } elseif ($actions->row->status === ACTIVITY_STATUS::ENDED) {
+                    $actions->append('<a href="' . admin_url('activity/activities/' . $actions->getKey() . '/close') . '"><i class="fa fa-times"></i> 关闭</a>');
+                }
+            });
+        });
+    }
+
+    /**
+     * 创建详情页
+     *
+     * @param mixed $id
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new ActivityConfigRepository(), function (Show $show) {
+            $show->field('id', 'ID');
+            $show->field('name', '活动名称');
+            $show->field('type', '活动类型')->as(function ($type) {
+                return ACTIVITY_TYPE::getName($type);
+            });
+            $show->field('description', '活动描述');
+            $show->field('start_time', '开始时间');
+            $show->field('end_time', '结束时间');
+            $show->field('status', '状态')->as(function ($status) {
+                return ACTIVITY_STATUS::getName($status);
+            });
+            $show->field('display_order', '显示顺序');
+            $show->field('icon', '活动图标')->image();
+            $show->field('banner', '活动横幅')->image();
+            $show->field('reward_group_id', '奖励组ID');
+            $show->field('reward_group_code', '奖励组编码');
+            $show->field('config_params', '配置参数')->json();
+            $show->field('created_at', '创建时间');
+            $show->field('updated_at', '更新时间');
+
+            // 显示活动条件
+            $show->divider();
+            $show->field('条件')->as(function () {
+                $conditions = $this->conditions()->get();
+                if ($conditions->isEmpty()) {
+                    return '无条件';
+                }
+
+                $headers = ['ID', '条件类型', '参与条件', '完成条件', '显示顺序'];
+                $rows = [];
+
+                foreach ($conditions as $condition) {
+                    $rows[] = [
+                        $condition->id,
+                        $condition->getConditionTypeName(),
+                        $condition->is_participation_condition ? '是' : '否',
+                        $condition->is_completion_condition ? '是' : '否',
+                        $condition->display_order
+                    ];
+                }
+
+                return Card::make(
+                    Table::make($headers, $rows)
+                );
+            });
+
+            // 显示奖励信息
+            $show->divider();
+            $show->field('奖励信息')->as(function () {
+                if (!$this->reward_group_id && !$this->reward_group_code) {
+                    return '未配置奖励';
+                }
+
+                $rewardInfo = '奖励组ID: ' . ($this->reward_group_id ?: '无') . '<br>';
+                $rewardInfo .= '奖励组编码: ' . ($this->reward_group_code ?: '无') . '<br>';
+
+                // 这里可以调用奖励组服务获取更详细的奖励信息
+                // 由于没有实际的奖励组服务,这里只返回基本信息
+                return $rewardInfo;
+            })->unescape();
+        });
+    }
+
+    /**
+     * 创建表单
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new ActivityConfigRepository(), function (Form $form) {
+            $form->display('id', 'ID');
+            $form->text('name', '活动名称')->required();
+            $form->select('type', '活动类型')->options(ACTIVITY_TYPE::getAll())->required();
+            $form->textarea('description', '活动描述');
+            $form->datetime('start_time', '开始时间')->required();
+            $form->datetime('end_time', '结束时间')->required();
+            $form->select('status', '状态')->options(ACTIVITY_STATUS::getAll())->default(ACTIVITY_STATUS::NOT_STARTED);
+            $form->number('display_order', '显示顺序')->default(0);
+            $form->image('icon', '活动图标')->autoUpload();
+            $form->image('banner', '活动横幅')->autoUpload();
+            
+            // 奖励组选择
+            $form->divider('奖励配置');
+            $form->number('reward_group_id', '奖励组ID')->help('填写奖励组ID或奖励组编码,两者选其一即可');
+            $form->text('reward_group_code', '奖励组编码')->help('填写奖励组ID或奖励组编码,两者选其一即可');
+            
+            // 活动条件
+            $form->divider('活动条件');
+            $form->hasMany('conditions', '条件', function (Form\NestedForm $form) {
+                $form->select('condition_type', '条件类型')->options(\App\Module\Activity\Enums\CONDITION_TYPE::getAll())->required();
+                $form->textarea('condition_params', '条件参数')->help('JSON格式,根据条件类型填写不同的参数');
+                $form->switch('is_participation_condition', '参与条件')->default(false);
+                $form->switch('is_completion_condition', '完成条件')->default(false);
+                $form->number('display_order', '显示顺序')->default(0);
+            });
+            
+            // 高级配置
+            $form->divider('高级配置');
+            $form->textarea('config_params', '配置参数')->help('JSON格式,用于存储活动特定的配置参数');
+
+            $form->display('created_at', '创建时间');
+            $form->display('updated_at', '更新时间');
+        });
+    }
+
+    /**
+     * 复制活动
+     *
+     * @param int $id
+     * @param Content $content
+     * @return Content
+     */
+    public function duplicate($id, Content $content)
+    {
+        $activity = ActivityConfig::with('conditions')->findOrFail($id);
+        
+        // 复制活动基本信息
+        $newActivity = $activity->replicate();
+        $newActivity->name = $activity->name . ' (复制)';
+        $newActivity->status = ACTIVITY_STATUS::NOT_STARTED;
+        $newActivity->save();
+        
+        // 复制活动条件
+        foreach ($activity->conditions as $condition) {
+            $newCondition = $condition->replicate();
+            $newCondition->activity_id = $newActivity->id;
+            $newCondition->save();
+        }
+        
+        return $content
+            ->title($this->title())
+            ->description('复制活动')
+            ->body(admin_success('复制成功', "已成功复制活动 [{$newActivity->name}]"))
+            ->body("<script>setTimeout(function(){ window.location.href = '" . admin_url('activity/activities') . "'; }, 2000);</script>");
+    }
+
+    /**
+     * 开始活动
+     *
+     * @param int $id
+     * @param Content $content
+     * @return Content
+     */
+    public function start($id, Content $content)
+    {
+        $activity = ActivityConfig::findOrFail($id);
+        
+        if ($activity->status !== ACTIVITY_STATUS::NOT_STARTED) {
+            return $content
+                ->title($this->title())
+                ->description('开始活动')
+                ->body(admin_error('操作失败', '只有未开始的活动才能开始'));
+        }
+        
+        $activity->status = ACTIVITY_STATUS::IN_PROGRESS;
+        $activity->save();
+        
+        // 触发活动状态变更事件
+        event(new \App\Module\Activity\Events\ActivityStatusChangedEvent(
+            $activity->id,
+            ACTIVITY_STATUS::NOT_STARTED,
+            ACTIVITY_STATUS::IN_PROGRESS
+        ));
+        
+        return $content
+            ->title($this->title())
+            ->description('开始活动')
+            ->body(admin_success('操作成功', "活动 [{$activity->name}] 已开始"))
+            ->body("<script>setTimeout(function(){ window.location.href = '" . admin_url('activity/activities') . "'; }, 2000);</script>");
+    }
+
+    /**
+     * 结束活动
+     *
+     * @param int $id
+     * @param Content $content
+     * @return Content
+     */
+    public function end($id, Content $content)
+    {
+        $activity = ActivityConfig::findOrFail($id);
+        
+        if ($activity->status !== ACTIVITY_STATUS::IN_PROGRESS) {
+            return $content
+                ->title($this->title())
+                ->description('结束活动')
+                ->body(admin_error('操作失败', '只有进行中的活动才能结束'));
+        }
+        
+        $activity->status = ACTIVITY_STATUS::ENDED;
+        $activity->save();
+        
+        // 触发活动状态变更事件
+        event(new \App\Module\Activity\Events\ActivityStatusChangedEvent(
+            $activity->id,
+            ACTIVITY_STATUS::IN_PROGRESS,
+            ACTIVITY_STATUS::ENDED
+        ));
+        
+        return $content
+            ->title($this->title())
+            ->description('结束活动')
+            ->body(admin_success('操作成功', "活动 [{$activity->name}] 已结束"))
+            ->body("<script>setTimeout(function(){ window.location.href = '" . admin_url('activity/activities') . "'; }, 2000);</script>");
+    }
+
+    /**
+     * 关闭活动
+     *
+     * @param int $id
+     * @param Content $content
+     * @return Content
+     */
+    public function close($id, Content $content)
+    {
+        $activity = ActivityConfig::findOrFail($id);
+        
+        if ($activity->status !== ACTIVITY_STATUS::ENDED) {
+            return $content
+                ->title($this->title())
+                ->description('关闭活动')
+                ->body(admin_error('操作失败', '只有已结束的活动才能关闭'));
+        }
+        
+        $activity->status = ACTIVITY_STATUS::CLOSED;
+        $activity->save();
+        
+        // 触发活动状态变更事件
+        event(new \App\Module\Activity\Events\ActivityStatusChangedEvent(
+            $activity->id,
+            ACTIVITY_STATUS::ENDED,
+            ACTIVITY_STATUS::CLOSED
+        ));
+        
+        return $content
+            ->title($this->title())
+            ->description('关闭活动')
+            ->body(admin_success('操作成功', "活动 [{$activity->name}] 已关闭"))
+            ->body("<script>setTimeout(function(){ window.location.href = '" . admin_url('activity/activities') . "'; }, 2000);</script>");
+    }
+}

+ 279 - 0
app/Module/Activity/AdminControllers/ActivityParticipationController.php

@@ -0,0 +1,279 @@
+<?php
+
+namespace App\Module\Activity\AdminControllers;
+
+use App\Module\Activity\Enums\PARTICIPATION_STATUS;
+use App\Module\Activity\Enums\REWARD_STATUS;
+use App\Module\Activity\Models\ActivityConfig;
+use App\Module\Activity\Models\ActivityParticipation;
+use App\Module\Activity\Repositorys\ActivityParticipationRepository;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Layout\Content;
+
+/**
+ * 活动参与记录控制器
+ */
+class ActivityParticipationController extends AdminController
+{
+    /**
+     * 标题
+     *
+     * @return string
+     */
+    protected function title()
+    {
+        return '活动参与记录';
+    }
+
+    /**
+     * 创建表格
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(new ActivityParticipationRepository(), function (Grid $grid) {
+            $grid->column('id', 'ID')->sortable();
+            $grid->column('user_id', '用户ID');
+            $grid->column('activity_id', '活动')->display(function ($activityId) {
+                $activity = ActivityConfig::find($activityId);
+                return $activity ? $activity->name : "未知活动({$activityId})";
+            });
+            $grid->column('participate_time', '参与时间')->sortable();
+            $grid->column('completion_status', '完成状态')->display(function ($status) {
+                return PARTICIPATION_STATUS::getName($status);
+            })->label([
+                PARTICIPATION_STATUS::IN_PROGRESS => 'primary',
+                PARTICIPATION_STATUS::COMPLETED => 'success',
+                PARTICIPATION_STATUS::FAILED => 'danger',
+            ]);
+            $grid->column('completion_time', '完成时间');
+            $grid->column('reward_status', '奖励状态')->display(function ($status) {
+                return REWARD_STATUS::getName($status);
+            })->label([
+                REWARD_STATUS::NOT_CLAIMED => 'warning',
+                REWARD_STATUS::CLAIMED => 'success',
+                REWARD_STATUS::EXPIRED => 'danger',
+            ]);
+            $grid->column('created_at', '创建时间');
+            $grid->column('updated_at', '更新时间');
+
+            $grid->filter(function (Grid\Filter $filter) {
+                $filter->equal('id', 'ID');
+                $filter->equal('user_id', '用户ID');
+                $filter->equal('activity_id', '活动')->select(
+                    ActivityConfig::pluck('name', 'id')
+                );
+                $filter->equal('completion_status', '完成状态')->select(PARTICIPATION_STATUS::getAll());
+                $filter->equal('reward_status', '奖励状态')->select(REWARD_STATUS::getAll());
+                $filter->between('participate_time', '参与时间')->datetime();
+                $filter->between('completion_time', '完成时间')->datetime();
+            });
+
+            // 禁用创建按钮
+            $grid->disableCreateButton();
+            
+            // 添加操作按钮
+            $grid->actions(function (Grid\Displayers\Actions $actions) {
+                // 如果未完成,添加标记为完成按钮
+                if ($actions->row->completion_status === PARTICIPATION_STATUS::IN_PROGRESS) {
+                    $actions->append('<a href="' . admin_url('activity/participations/' . $actions->getKey() . '/complete') . '"><i class="fa fa-check"></i> 标记完成</a>');
+                }
+                
+                // 如果已完成但未领取奖励,添加标记为已领取按钮
+                if ($actions->row->completion_status === PARTICIPATION_STATUS::COMPLETED && $actions->row->reward_status === REWARD_STATUS::NOT_CLAIMED) {
+                    $actions->append('<a href="' . admin_url('activity/participations/' . $actions->getKey() . '/claim') . '"><i class="fa fa-gift"></i> 标记已领取</a>');
+                }
+                
+                // 如果未领取奖励,添加标记为已过期按钮
+                if ($actions->row->reward_status === REWARD_STATUS::NOT_CLAIMED) {
+                    $actions->append('<a href="' . admin_url('activity/participations/' . $actions->getKey() . '/expire') . '"><i class="fa fa-clock-o"></i> 标记已过期</a>');
+                }
+            });
+        });
+    }
+
+    /**
+     * 创建详情页
+     *
+     * @param mixed $id
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new ActivityParticipationRepository(), function (Show $show) {
+            $show->field('id', 'ID');
+            $show->field('user_id', '用户ID');
+            $show->field('activity_id', '活动')->as(function ($activityId) {
+                $activity = ActivityConfig::find($activityId);
+                return $activity ? $activity->name : "未知活动({$activityId})";
+            });
+            $show->field('participate_time', '参与时间');
+            $show->field('completion_status', '完成状态')->as(function ($status) {
+                return PARTICIPATION_STATUS::getName($status);
+            });
+            $show->field('completion_time', '完成时间');
+            $show->field('reward_status', '奖励状态')->as(function ($status) {
+                return REWARD_STATUS::getName($status);
+            });
+            $show->field('created_at', '创建时间');
+            $show->field('updated_at', '更新时间');
+
+            // 显示用户活动数据
+            $show->divider();
+            $show->field('用户活动数据')->as(function () {
+                $userData = \App\Module\Activity\Models\UserActivityData::where('user_id', $this->user_id)
+                    ->where('activity_id', $this->activity_id)
+                    ->first();
+                
+                if (!$userData) {
+                    return '无数据';
+                }
+                
+                $html = '<div class="table-responsive"><table class="table table-bordered">';
+                $html .= '<tr><th>进度</th><td>' . $userData->progress . '</td></tr>';
+                $html .= '<tr><th>最后更新</th><td>' . $userData->last_update . '</td></tr>';
+                $html .= '<tr><th>详细进度数据</th><td><pre>' . json_encode($userData->progress_data, JSON_PRETTY_PRINT) . '</pre></td></tr>';
+                $html .= '</table></div>';
+                
+                return $html;
+            })->unescape();
+        });
+    }
+
+    /**
+     * 创建表单
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new ActivityParticipationRepository(), function (Form $form) {
+            $form->display('id', 'ID');
+            $form->display('user_id', '用户ID');
+            $form->display('activity_id', '活动ID');
+            $form->display('participate_time', '参与时间');
+            
+            $form->select('completion_status', '完成状态')
+                ->options(PARTICIPATION_STATUS::getAll())
+                ->required();
+            
+            $form->datetime('completion_time', '完成时间');
+            
+            $form->select('reward_status', '奖励状态')
+                ->options(REWARD_STATUS::getAll())
+                ->required();
+            
+            $form->display('created_at', '创建时间');
+            $form->display('updated_at', '更新时间');
+        });
+    }
+
+    /**
+     * 标记为完成
+     *
+     * @param int $id
+     * @param Content $content
+     * @return Content
+     */
+    public function complete($id, Content $content)
+    {
+        $participation = ActivityParticipation::findOrFail($id);
+        
+        if ($participation->completion_status !== PARTICIPATION_STATUS::IN_PROGRESS) {
+            return $content
+                ->title($this->title())
+                ->description('标记完成')
+                ->body(admin_error('操作失败', '只有进行中的参与记录才能标记为完成'));
+        }
+        
+        $participation->completion_status = PARTICIPATION_STATUS::COMPLETED;
+        $participation->completion_time = now();
+        $participation->save();
+        
+        // 触发活动完成事件
+        event(new \App\Module\Activity\Events\ActivityCompletedEvent(
+            $participation->user_id,
+            $participation->activity_id
+        ));
+        
+        return $content
+            ->title($this->title())
+            ->description('标记完成')
+            ->body(admin_success('操作成功', "参与记录 [{$id}] 已标记为完成"))
+            ->body("<script>setTimeout(function(){ window.location.href = '" . admin_url('activity/participations') . "'; }, 2000);</script>");
+    }
+
+    /**
+     * 标记为已领取
+     *
+     * @param int $id
+     * @param Content $content
+     * @return Content
+     */
+    public function claim($id, Content $content)
+    {
+        $participation = ActivityParticipation::findOrFail($id);
+        
+        if ($participation->completion_status !== PARTICIPATION_STATUS::COMPLETED) {
+            return $content
+                ->title($this->title())
+                ->description('标记已领取')
+                ->body(admin_error('操作失败', '只有已完成的参与记录才能标记为已领取'));
+        }
+        
+        if ($participation->reward_status !== REWARD_STATUS::NOT_CLAIMED) {
+            return $content
+                ->title($this->title())
+                ->description('标记已领取')
+                ->body(admin_error('操作失败', '只有未领取的奖励才能标记为已领取'));
+        }
+        
+        $participation->reward_status = REWARD_STATUS::CLAIMED;
+        $participation->save();
+        
+        // 触发奖励领取事件
+        event(new \App\Module\Activity\Events\ActivityRewardClaimedEvent(
+            $participation->user_id,
+            $participation->activity_id,
+            ['success' => true, 'message' => '管理员手动标记', 'rewards' => []]
+        ));
+        
+        return $content
+            ->title($this->title())
+            ->description('标记已领取')
+            ->body(admin_success('操作成功', "参与记录 [{$id}] 的奖励已标记为已领取"))
+            ->body("<script>setTimeout(function(){ window.location.href = '" . admin_url('activity/participations') . "'; }, 2000);</script>");
+    }
+
+    /**
+     * 标记为已过期
+     *
+     * @param int $id
+     * @param Content $content
+     * @return Content
+     */
+    public function expire($id, Content $content)
+    {
+        $participation = ActivityParticipation::findOrFail($id);
+        
+        if ($participation->reward_status !== REWARD_STATUS::NOT_CLAIMED) {
+            return $content
+                ->title($this->title())
+                ->description('标记已过期')
+                ->body(admin_error('操作失败', '只有未领取的奖励才能标记为已过期'));
+        }
+        
+        $participation->reward_status = REWARD_STATUS::EXPIRED;
+        $participation->save();
+        
+        return $content
+            ->title($this->title())
+            ->description('标记已过期')
+            ->body(admin_success('操作成功', "参与记录 [{$id}] 的奖励已标记为已过期"))
+            ->body("<script>setTimeout(function(){ window.location.href = '" . admin_url('activity/participations') . "'; }, 2000);</script>");
+    }
+}

+ 123 - 0
app/Module/Activity/AdminControllers/UserActivityDataController.php

@@ -0,0 +1,123 @@
+<?php
+
+namespace App\Module\Activity\AdminControllers;
+
+use App\Module\Activity\Models\ActivityConfig;
+use App\Module\Activity\Repositorys\UserActivityDataRepository;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+
+/**
+ * 用户活动数据控制器
+ */
+class UserActivityDataController extends AdminController
+{
+    /**
+     * 标题
+     *
+     * @return string
+     */
+    protected function title()
+    {
+        return '用户活动数据';
+    }
+
+    /**
+     * 创建表格
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(new UserActivityDataRepository(), function (Grid $grid) {
+            $grid->column('id', 'ID')->sortable();
+            $grid->column('user_id', '用户ID');
+            $grid->column('activity_id', '活动')->display(function ($activityId) {
+                $activity = ActivityConfig::find($activityId);
+                return $activity ? $activity->name : "未知活动({$activityId})";
+            });
+            $grid->column('progress', '进度');
+            $grid->column('last_update', '最后更新时间')->sortable();
+            $grid->column('created_at', '创建时间');
+            $grid->column('updated_at', '更新时间');
+
+            $grid->filter(function (Grid\Filter $filter) {
+                $filter->equal('id', 'ID');
+                $filter->equal('user_id', '用户ID');
+                $filter->equal('activity_id', '活动')->select(
+                    ActivityConfig::pluck('name', 'id')
+                );
+                $filter->between('last_update', '最后更新时间')->datetime();
+            });
+
+            // 禁用创建按钮
+            $grid->disableCreateButton();
+        });
+    }
+
+    /**
+     * 创建详情页
+     *
+     * @param mixed $id
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new UserActivityDataRepository(), function (Show $show) {
+            $show->field('id', 'ID');
+            $show->field('user_id', '用户ID');
+            $show->field('activity_id', '活动')->as(function ($activityId) {
+                $activity = ActivityConfig::find($activityId);
+                return $activity ? $activity->name : "未知活动({$activityId})";
+            });
+            $show->field('progress', '进度');
+            $show->field('progress_data', '进度数据')->json();
+            $show->field('last_update', '最后更新时间');
+            $show->field('created_at', '创建时间');
+            $show->field('updated_at', '更新时间');
+
+            // 显示参与记录
+            $show->divider();
+            $show->field('参与记录')->as(function () {
+                $participation = \App\Module\Activity\Models\ActivityParticipation::where('user_id', $this->user_id)
+                    ->where('activity_id', $this->activity_id)
+                    ->first();
+                
+                if (!$participation) {
+                    return '无参与记录';
+                }
+                
+                $html = '<div class="table-responsive"><table class="table table-bordered">';
+                $html .= '<tr><th>ID</th><td>' . $participation->id . '</td></tr>';
+                $html .= '<tr><th>参与时间</th><td>' . $participation->participate_time . '</td></tr>';
+                $html .= '<tr><th>完成状态</th><td>' . \App\Module\Activity\Enums\PARTICIPATION_STATUS::getName($participation->completion_status) . '</td></tr>';
+                $html .= '<tr><th>完成时间</th><td>' . ($participation->completion_time ?: '未完成') . '</td></tr>';
+                $html .= '<tr><th>奖励状态</th><td>' . \App\Module\Activity\Enums\REWARD_STATUS::getName($participation->reward_status) . '</td></tr>';
+                $html .= '</table></div>';
+                
+                return $html;
+            })->unescape();
+        });
+    }
+
+    /**
+     * 创建表单
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new UserActivityDataRepository(), function (Form $form) {
+            $form->display('id', 'ID');
+            $form->display('user_id', '用户ID');
+            $form->display('activity_id', '活动ID');
+            $form->number('progress', '进度')->min(0);
+            $form->textarea('progress_data', '进度数据')->help('JSON格式');
+            $form->display('last_update', '最后更新时间');
+            $form->display('created_at', '创建时间');
+            $form->display('updated_at', '更新时间');
+        });
+    }
+}

+ 139 - 0
app/Module/Activity/Commands/CleanExpiredActivitiesCommand.php

@@ -0,0 +1,139 @@
+<?php
+
+namespace App\Module\Activity\Commands;
+
+use App\Module\Activity\Enums\ACTIVITY_STATUS;
+use App\Module\Activity\Enums\REWARD_STATUS;
+use App\Module\Activity\Models\ActivityConfig;
+use App\Module\Activity\Models\ActivityParticipation;
+use Carbon\Carbon;
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+
+/**
+ * 清理过期活动命令
+ */
+class CleanExpiredActivitiesCommand extends Command
+{
+    /**
+     * 命令名称
+     *
+     * @var string
+     */
+    protected $signature = 'activity:clean-expired {--days=30 : 清理多少天前结束的活动} {--dry-run : 仅显示将要清理的内容,不实际执行}';
+
+    /**
+     * 命令描述
+     *
+     * @var string
+     */
+    protected $description = '清理过期活动和未领取的奖励';
+
+    /**
+     * 执行命令
+     *
+     * @return int
+     */
+    public function handle()
+    {
+        $days = (int)$this->option('days');
+        $dryRun = $this->option('dry-run');
+        
+        if ($days <= 0) {
+            $this->error('天数必须大于0');
+            return 1;
+        }
+        
+        $cutoffDate = Carbon::now()->subDays($days);
+        $this->info("开始清理 {$cutoffDate} 之前结束的活动...");
+        
+        if ($dryRun) {
+            $this->warn('当前为演示模式,不会实际执行清理操作');
+        }
+        
+        // 查找过期活动
+        $expiredActivities = ActivityConfig::where('end_time', '<', $cutoffDate)
+            ->whereIn('status', [ACTIVITY_STATUS::ENDED, ACTIVITY_STATUS::CLOSED])
+            ->get();
+        
+        $this->info("找到 " . count($expiredActivities) . " 个过期活动");
+        
+        if ($expiredActivities->isEmpty()) {
+            $this->info('没有需要清理的过期活动');
+            return 0;
+        }
+        
+        // 显示将要清理的活动
+        $this->table(
+            ['ID', '名称', '结束时间', '状态'],
+            $expiredActivities->map(function ($activity) {
+                return [
+                    $activity->id,
+                    $activity->name,
+                    $activity->end_time,
+                    ACTIVITY_STATUS::getName($activity->status)
+                ];
+            })
+        );
+        
+        if (!$dryRun && !$this->confirm('确定要清理这些活动吗?此操作不可撤销')) {
+            $this->info('操作已取消');
+            return 0;
+        }
+        
+        // 清理过期活动
+        $expiredActivityIds = $expiredActivities->pluck('id')->toArray();
+        $expiredRewardsCount = 0;
+        
+        if (!$dryRun) {
+            DB::beginTransaction();
+            
+            try {
+                // 标记未领取的奖励为已过期
+                $expiredRewardsCount = ActivityParticipation::whereIn('activity_id', $expiredActivityIds)
+                    ->where('reward_status', REWARD_STATUS::NOT_CLAIMED)
+                    ->update(['reward_status' => REWARD_STATUS::EXPIRED]);
+                
+                // 更新活动状态为已关闭
+                ActivityConfig::whereIn('id', $expiredActivityIds)
+                    ->where('status', ACTIVITY_STATUS::ENDED)
+                    ->update(['status' => ACTIVITY_STATUS::CLOSED]);
+                
+                DB::commit();
+                
+                $this->info("成功清理 " . count($expiredActivityIds) . " 个过期活动");
+                $this->info("标记 {$expiredRewardsCount} 个未领取的奖励为已过期");
+                
+                // 记录日志
+                Log::info("清理过期活动完成", [
+                    'activity_count' => count($expiredActivityIds),
+                    'expired_rewards_count' => $expiredRewardsCount,
+                    'cutoff_date' => $cutoffDate
+                ]);
+            } catch (\Exception $e) {
+                DB::rollBack();
+                
+                $this->error("清理过期活动失败: " . $e->getMessage());
+                
+                // 记录日志
+                Log::error("清理过期活动失败", [
+                    'error' => $e->getMessage(),
+                    'cutoff_date' => $cutoffDate
+                ]);
+                
+                return 1;
+            }
+        } else {
+            // 演示模式,显示将要执行的操作
+            $expiredRewardsCount = ActivityParticipation::whereIn('activity_id', $expiredActivityIds)
+                ->where('reward_status', REWARD_STATUS::NOT_CLAIMED)
+                ->count();
+            
+            $this->info("将会清理 " . count($expiredActivityIds) . " 个过期活动");
+            $this->info("将会标记 {$expiredRewardsCount} 个未领取的奖励为已过期");
+        }
+        
+        return 0;
+    }
+}

+ 219 - 0
app/Module/Activity/Commands/GenerateActivityReportCommand.php

@@ -0,0 +1,219 @@
+<?php
+
+namespace App\Module\Activity\Commands;
+
+use App\Module\Activity\Enums\ACTIVITY_STATUS;
+use App\Module\Activity\Enums\PARTICIPATION_STATUS;
+use App\Module\Activity\Enums\REWARD_STATUS;
+use App\Module\Activity\Models\ActivityConfig;
+use App\Module\Activity\Models\ActivityParticipation;
+use App\Module\Activity\Models\UserActivityData;
+use Carbon\Carbon;
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\File;
+
+/**
+ * 生成活动报告命令
+ */
+class GenerateActivityReportCommand extends Command
+{
+    /**
+     * 命令名称
+     *
+     * @var string
+     */
+    protected $signature = 'activity:report {activity_id? : 活动ID,不指定则生成所有活动的报告} {--output=storage/activity_reports : 报告输出目录}';
+
+    /**
+     * 命令描述
+     *
+     * @var string
+     */
+    protected $description = '生成活动参与和完成情况报告';
+
+    /**
+     * 执行命令
+     *
+     * @return int
+     */
+    public function handle()
+    {
+        $activityId = $this->argument('activity_id');
+        $outputDir = $this->option('output');
+        
+        // 创建输出目录
+        if (!File::exists($outputDir)) {
+            File::makeDirectory($outputDir, 0755, true);
+        }
+        
+        // 获取活动列表
+        if ($activityId) {
+            $activities = ActivityConfig::where('id', $activityId)->get();
+            
+            if ($activities->isEmpty()) {
+                $this->error("活动 ID {$activityId} 不存在");
+                return 1;
+            }
+        } else {
+            $activities = ActivityConfig::all();
+            
+            if ($activities->isEmpty()) {
+                $this->info("没有找到任何活动");
+                return 0;
+            }
+        }
+        
+        $this->info("开始生成 " . count($activities) . " 个活动的报告...");
+        
+        $timestamp = Carbon::now()->format('YmdHis');
+        $summaryData = [];
+        
+        foreach ($activities as $activity) {
+            $this->info("正在处理活动: [{$activity->id}] {$activity->name}");
+            
+            // 收集活动数据
+            $participantCount = ActivityParticipation::where('activity_id', $activity->id)
+                ->distinct('user_id')
+                ->count('user_id');
+            
+            $completedCount = ActivityParticipation::where('activity_id', $activity->id)
+                ->where('completion_status', PARTICIPATION_STATUS::COMPLETED)
+                ->count();
+            
+            $inProgressCount = ActivityParticipation::where('activity_id', $activity->id)
+                ->where('completion_status', PARTICIPATION_STATUS::IN_PROGRESS)
+                ->count();
+            
+            $failedCount = ActivityParticipation::where('activity_id', $activity->id)
+                ->where('completion_status', PARTICIPATION_STATUS::FAILED)
+                ->count();
+            
+            $rewardClaimedCount = ActivityParticipation::where('activity_id', $activity->id)
+                ->where('reward_status', REWARD_STATUS::CLAIMED)
+                ->count();
+            
+            $rewardNotClaimedCount = ActivityParticipation::where('activity_id', $activity->id)
+                ->where('reward_status', REWARD_STATUS::NOT_CLAIMED)
+                ->count();
+            
+            $rewardExpiredCount = ActivityParticipation::where('activity_id', $activity->id)
+                ->where('reward_status', REWARD_STATUS::EXPIRED)
+                ->count();
+            
+            // 计算平均进度
+            $averageProgress = UserActivityData::where('activity_id', $activity->id)
+                ->avg('progress') ?: 0;
+            
+            // 计算完成率
+            $completionRate = $participantCount > 0 ? round(($completedCount / $participantCount) * 100, 2) : 0;
+            
+            // 计算奖励领取率
+            $rewardClaimRate = $completedCount > 0 ? round(($rewardClaimedCount / $completedCount) * 100, 2) : 0;
+            
+            // 收集每日参与数据
+            $dailyParticipations = DB::table('activity_participation')
+                ->select(DB::raw('DATE(participate_time) as date'), DB::raw('COUNT(*) as count'))
+                ->where('activity_id', $activity->id)
+                ->groupBy('date')
+                ->orderBy('date')
+                ->get();
+            
+            // 收集每日完成数据
+            $dailyCompletions = DB::table('activity_participation')
+                ->select(DB::raw('DATE(completion_time) as date'), DB::raw('COUNT(*) as count'))
+                ->where('activity_id', $activity->id)
+                ->where('completion_status', PARTICIPATION_STATUS::COMPLETED)
+                ->groupBy('date')
+                ->orderBy('date')
+                ->get();
+            
+            // 生成报告内容
+            $reportContent = "# 活动报告: [{$activity->id}] {$activity->name}\n\n";
+            $reportContent .= "生成时间: " . Carbon::now()->toDateTimeString() . "\n\n";
+            
+            $reportContent .= "## 活动基本信息\n\n";
+            $reportContent .= "- 活动ID: {$activity->id}\n";
+            $reportContent .= "- 活动名称: {$activity->name}\n";
+            $reportContent .= "- 活动类型: " . \App\Module\Activity\Enums\ACTIVITY_TYPE::getName($activity->type) . "\n";
+            $reportContent .= "- 开始时间: {$activity->start_time}\n";
+            $reportContent .= "- 结束时间: {$activity->end_time}\n";
+            $reportContent .= "- 当前状态: " . ACTIVITY_STATUS::getName($activity->status) . "\n";
+            
+            $reportContent .= "\n## 参与情况统计\n\n";
+            $reportContent .= "- 总参与人数: {$participantCount}\n";
+            $reportContent .= "- 已完成人数: {$completedCount}\n";
+            $reportContent .= "- 进行中人数: {$inProgressCount}\n";
+            $reportContent .= "- 已失败人数: {$failedCount}\n";
+            $reportContent .= "- 完成率: {$completionRate}%\n";
+            $reportContent .= "- 平均进度: " . round($averageProgress, 2) . "\n";
+            
+            $reportContent .= "\n## 奖励领取情况\n\n";
+            $reportContent .= "- 已领取奖励人数: {$rewardClaimedCount}\n";
+            $reportContent .= "- 未领取奖励人数: {$rewardNotClaimedCount}\n";
+            $reportContent .= "- 已过期奖励人数: {$rewardExpiredCount}\n";
+            $reportContent .= "- 奖励领取率: {$rewardClaimRate}%\n";
+            
+            $reportContent .= "\n## 每日参与人数\n\n";
+            $reportContent .= "| 日期 | 参与人数 |\n";
+            $reportContent .= "|------|--------|\n";
+            
+            foreach ($dailyParticipations as $data) {
+                $reportContent .= "| {$data->date} | {$data->count} |\n";
+            }
+            
+            $reportContent .= "\n## 每日完成人数\n\n";
+            $reportContent .= "| 日期 | 完成人数 |\n";
+            $reportContent .= "|------|--------|\n";
+            
+            foreach ($dailyCompletions as $data) {
+                $reportContent .= "| {$data->date} | {$data->count} |\n";
+            }
+            
+            // 保存报告文件
+            $filename = "activity_{$activity->id}_report_{$timestamp}.md";
+            $filePath = "{$outputDir}/{$filename}";
+            
+            File::put($filePath, $reportContent);
+            
+            $this->info("活动报告已保存到: {$filePath}");
+            
+            // 收集汇总数据
+            $summaryData[] = [
+                'id' => $activity->id,
+                'name' => $activity->name,
+                'status' => ACTIVITY_STATUS::getName($activity->status),
+                'participants' => $participantCount,
+                'completed' => $completedCount,
+                'completion_rate' => $completionRate . '%',
+                'rewards_claimed' => $rewardClaimedCount,
+                'claim_rate' => $rewardClaimRate . '%'
+            ];
+        }
+        
+        // 生成汇总报告
+        if (count($activities) > 1) {
+            $summaryContent = "# 活动汇总报告\n\n";
+            $summaryContent .= "生成时间: " . Carbon::now()->toDateTimeString() . "\n\n";
+            $summaryContent .= "## 活动列表\n\n";
+            $summaryContent .= "| ID | 活动名称 | 状态 | 参与人数 | 完成人数 | 完成率 | 领取奖励人数 | 领取率 |\n";
+            $summaryContent .= "|----|---------|----|--------|--------|-------|------------|-------|\n";
+            
+            foreach ($summaryData as $data) {
+                $summaryContent .= "| {$data['id']} | {$data['name']} | {$data['status']} | {$data['participants']} | {$data['completed']} | {$data['completion_rate']} | {$data['rewards_claimed']} | {$data['claim_rate']} |\n";
+            }
+            
+            // 保存汇总报告
+            $summaryFilename = "activity_summary_report_{$timestamp}.md";
+            $summaryFilePath = "{$outputDir}/{$summaryFilename}";
+            
+            File::put($summaryFilePath, $summaryContent);
+            
+            $this->info("汇总报告已保存到: {$summaryFilePath}");
+        }
+        
+        $this->info("活动报告生成完成");
+        
+        return 0;
+    }
+}

+ 110 - 0
app/Module/Activity/Commands/UpdateActivityStatusCommand.php

@@ -0,0 +1,110 @@
+<?php
+
+namespace App\Module\Activity\Commands;
+
+use App\Module\Activity\Enums\ACTIVITY_STATUS;
+use App\Module\Activity\Events\ActivityStatusChangedEvent;
+use App\Module\Activity\Models\ActivityConfig;
+use Carbon\Carbon;
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\Log;
+
+/**
+ * 更新活动状态命令
+ */
+class UpdateActivityStatusCommand extends Command
+{
+    /**
+     * 命令名称
+     *
+     * @var string
+     */
+    protected $signature = 'activity:update-status {--force : 强制更新所有活动状态}';
+
+    /**
+     * 命令描述
+     *
+     * @var string
+     */
+    protected $description = '根据时间自动更新活动状态';
+
+    /**
+     * 执行命令
+     *
+     * @return int
+     */
+    public function handle()
+    {
+        $this->info('开始更新活动状态...');
+        
+        $now = Carbon::now();
+        $updated = 0;
+        $force = $this->option('force');
+        
+        // 更新未开始的活动
+        $notStartedQuery = ActivityConfig::where('status', ACTIVITY_STATUS::NOT_STARTED);
+        
+        if (!$force) {
+            $notStartedQuery->where('start_time', '<=', $now);
+        }
+        
+        $notStartedActivities = $notStartedQuery->get();
+        
+        foreach ($notStartedActivities as $activity) {
+            $oldStatus = $activity->status;
+            
+            if ($force || $activity->start_time <= $now) {
+                $activity->status = ACTIVITY_STATUS::IN_PROGRESS;
+                $activity->save();
+                
+                // 触发活动状态变更事件
+                event(new ActivityStatusChangedEvent(
+                    $activity->id,
+                    $oldStatus,
+                    ACTIVITY_STATUS::IN_PROGRESS
+                ));
+                
+                $this->info("活动 [{$activity->id}] {$activity->name} 状态已更新为进行中");
+                $updated++;
+            }
+        }
+        
+        // 更新进行中的活动
+        $inProgressQuery = ActivityConfig::where('status', ACTIVITY_STATUS::IN_PROGRESS);
+        
+        if (!$force) {
+            $inProgressQuery->where('end_time', '<', $now);
+        }
+        
+        $inProgressActivities = $inProgressQuery->get();
+        
+        foreach ($inProgressActivities as $activity) {
+            $oldStatus = $activity->status;
+            
+            if ($force || $activity->end_time < $now) {
+                $activity->status = ACTIVITY_STATUS::ENDED;
+                $activity->save();
+                
+                // 触发活动状态变更事件
+                event(new ActivityStatusChangedEvent(
+                    $activity->id,
+                    $oldStatus,
+                    ACTIVITY_STATUS::ENDED
+                ));
+                
+                $this->info("活动 [{$activity->id}] {$activity->name} 状态已更新为已结束");
+                $updated++;
+            }
+        }
+        
+        $this->info("活动状态更新完成,共更新 {$updated} 个活动");
+        
+        // 记录日志
+        Log::info("活动状态更新完成", [
+            'updated_count' => $updated,
+            'force' => $force
+        ]);
+        
+        return 0;
+    }
+}

+ 123 - 0
app/Module/Activity/Docs/DEV.md

@@ -0,0 +1,123 @@
+# 活动模块开发计划
+
+## 1. 创建基本目录结构 ✅
+
+- [x] 确认 AdminControllers 目录
+- [x] 确认 Commands 目录
+- [x] 确认 Enums 目录
+- [x] 确认 Events 目录
+- [x] 确认 Logics 目录
+- [x] 确认 Models 目录
+- [x] 确认 Providers 目录
+- [x] 确认 Repositorys 目录
+- [x] 确认 Services 目录
+- [x] 确认 Dtos 目录
+
+## 2. 实现枚举类 ✅
+
+- [x] ACTIVITY_TYPE - 活动类型枚举(礼包活动、限时活动、任务活动等)
+- [x] ACTIVITY_STATUS - 活动状态枚举(未开始、进行中、已结束、已关闭)
+- [x] PARTICIPATION_STATUS - 参与状态枚举(进行中、已完成、已失败)
+- [x] REWARD_STATUS - 奖励状态枚举(未领取、已领取、已过期)
+- [x] CONDITION_TYPE - 条件类型枚举(等级要求、道具要求、时间要求等)
+
+## 3. 实现模型类 ✅
+
+- [x] ActivityConfig - 活动基础配置
+- [x] ActivityParticipation - 活动参与记录
+- [x] UserActivityData - 用户活动数据
+- [x] ActivityCondition - 活动条件
+
+## 4. 实现DTO ✅
+
+- [x] ActivityConfigDto - 活动配置DTO
+- [x] ActivityParticipationDto - 活动参与记录DTO
+- [x] UserActivityDataDto - 用户活动数据DTO
+- [x] ActivityConditionDto - 活动条件DTO
+- [x] ActivityRewardDto - 活动奖励DTO
+
+## 5. 实现数据仓库 ✅
+
+- [x] ActivityConfigRepository - 活动配置仓库
+- [x] ActivityParticipationRepository - 活动参与记录仓库
+- [x] UserActivityDataRepository - 用户活动数据仓库
+- [x] ActivityConditionRepository - 活动条件仓库
+
+## 6. 实现服务层和逻辑层 ✅
+
+### 6.1 逻辑层(内部)
+
+- [x] ActivityLogic - 活动核心逻辑
+- [x] RewardLogic - 奖励处理逻辑
+- [x] ParticipationLogic - 参与逻辑
+- [x] ProgressLogic - 进度逻辑
+- [x] ConditionLogic - 条件检查逻辑
+
+### 6.2 服务层(对外,静态方法)
+
+- [x] ActivityService - 活动服务
+- [x] RewardService - 奖励服务
+- [x] ActivityManagementService - 活动管理服务
+
+## 7. 实现事件和监听器 ✅
+
+### 7.1 事件
+
+- [x] ActivityCreatedEvent - 活动创建事件
+- [x] ActivityStatusChangedEvent - 活动状态变更事件
+- [x] UserParticipatedEvent - 用户参与活动事件
+- [x] ActivityProgressUpdatedEvent - 活动进度更新事件
+- [x] ActivityCompletedEvent - 活动完成事件
+- [x] ActivityRewardClaimedEvent - 活动奖励领取事件
+
+### 7.2 监听器
+
+- [x] ActivityStatusChangeListener - 活动状态变更监听器
+- [x] UserParticipationListener - 用户参与监听器
+- [x] ActivityProgressListener - 活动进度监听器
+- [x] ActivityCompletedListener - 活动完成监听器
+- [x] RewardDistributionListener - 奖励发放监听器
+
+## 8. 实现后台控制器 ✅
+
+- [x] ActivityController - 活动管理控制器
+- [x] ActivityParticipationController - 活动参与记录控制器
+- [x] UserActivityDataController - 用户活动数据控制器
+- [x] ActivityConditionController - 活动条件控制器
+
+## 9. 实现服务提供者 ✅
+
+- [x] ActivityServiceProvider - 注册服务、事件、命令等
+
+## 10. 实现命令行工具 ✅
+
+- [x] UpdateActivityStatusCommand - 更新活动状态命令
+- [x] CleanExpiredActivitiesCommand - 清理过期活动命令
+- [x] GenerateActivityReportCommand - 生成活动报告命令
+
+## 开发进度
+
+- ✅ 已完成
+- 🔄 进行中
+- ⏳ 待开始
+
+### 当前进度
+
+- 已完成活动模块文档设计
+- 已完成基本目录结构
+- 已完成枚举类实现
+- 已完成模型类实现
+- 已完成DTO类实现
+- 已完成数据仓库实现
+- 已完成逻辑层和服务层实现
+- 已完成事件和监听器实现
+- 已完成后台控制器实现
+- 已完成服务提供者实现
+- 已完成命令行工具实现
+- 活动模块开发完成
+
+### 下一步计划
+
+1. 编写单元测试
+2. 编写使用文档
+3. 与其他模块集成(奖励组、任务等)

+ 107 - 0
app/Module/Activity/Dtos/ActivityConditionDto.php

@@ -0,0 +1,107 @@
+<?php
+
+namespace App\Module\Activity\Dtos;
+
+use App\Module\Activity\Models\ActivityCondition;
+use UCore\Dto\BaseDto;
+
+/**
+ * 活动条件数据传输对象
+ */
+class ActivityConditionDto extends BaseDto
+{
+    /**
+     * 条件ID
+     *
+     * @var int
+     */
+    public int $id;
+
+    /**
+     * 活动ID
+     *
+     * @var int
+     */
+    public int $activityId;
+
+    /**
+     * 条件类型
+     *
+     * @var int
+     */
+    public int $conditionType;
+
+    /**
+     * 条件类型名称
+     *
+     * @var string
+     */
+    public string $conditionTypeName;
+
+    /**
+     * 条件参数
+     *
+     * @var array
+     */
+    public array $conditionParams = [];
+
+    /**
+     * 是否为参与条件
+     *
+     * @var bool
+     */
+    public bool $isParticipationCondition;
+
+    /**
+     * 是否为完成条件
+     *
+     * @var bool
+     */
+    public bool $isCompletionCondition;
+
+    /**
+     * 显示顺序
+     *
+     * @var int
+     */
+    public int $displayOrder;
+
+    /**
+     * 从模型创建DTO
+     *
+     * @param ActivityCondition $model 活动条件模型
+     * @return self
+     */
+    public static function fromModel(ActivityCondition $model): self
+    {
+        $dto = new self();
+        $dto->id = $model->id;
+        $dto->activityId = $model->activity_id;
+        $dto->conditionType = $model->condition_type;
+        $dto->conditionTypeName = $model->getConditionTypeName();
+        $dto->conditionParams = $model->condition_params ?? [];
+        $dto->isParticipationCondition = $model->isParticipationCondition();
+        $dto->isCompletionCondition = $model->isCompletionCondition();
+        $dto->displayOrder = $model->display_order;
+
+        return $dto;
+    }
+
+    /**
+     * 转换为模型数据数组
+     *
+     * @return array
+     */
+    public function toModelArray(): array
+    {
+        return [
+            'id' => $this->id ?? null,
+            'activity_id' => $this->activityId,
+            'condition_type' => $this->conditionType,
+            'condition_params' => $this->conditionParams,
+            'is_participation_condition' => $this->isParticipationCondition,
+            'is_completion_condition' => $this->isCompletionCondition,
+            'display_order' => $this->displayOrder,
+        ];
+    }
+}

+ 191 - 0
app/Module/Activity/Dtos/ActivityConfigDto.php

@@ -0,0 +1,191 @@
+<?php
+
+namespace App\Module\Activity\Dtos;
+
+use App\Module\Activity\Models\ActivityConfig;
+use UCore\Dto\BaseDto;
+
+/**
+ * 活动配置数据传输对象
+ */
+class ActivityConfigDto extends BaseDto
+{
+    /**
+     * 活动ID
+     *
+     * @var int
+     */
+    public int $id;
+
+    /**
+     * 活动名称
+     *
+     * @var string
+     */
+    public string $name;
+
+    /**
+     * 活动类型
+     *
+     * @var int
+     */
+    public int $type;
+
+    /**
+     * 活动类型名称
+     *
+     * @var string
+     */
+    public string $typeName;
+
+    /**
+     * 活动描述
+     *
+     * @var string
+     */
+    public string $description;
+
+    /**
+     * 开始时间
+     *
+     * @var string
+     */
+    public string $startTime;
+
+    /**
+     * 结束时间
+     *
+     * @var string
+     */
+    public string $endTime;
+
+    /**
+     * 活动状态
+     *
+     * @var int
+     */
+    public int $status;
+
+    /**
+     * 活动状态名称
+     *
+     * @var string
+     */
+    public string $statusName;
+
+    /**
+     * 显示顺序
+     *
+     * @var int
+     */
+    public int $displayOrder;
+
+    /**
+     * 活动图标URL
+     *
+     * @var string|null
+     */
+    public ?string $icon;
+
+    /**
+     * 活动横幅URL
+     *
+     * @var string|null
+     */
+    public ?string $banner;
+
+    /**
+     * 奖励组ID
+     *
+     * @var int|null
+     */
+    public ?int $rewardGroupId;
+
+    /**
+     * 奖励组编码
+     *
+     * @var string|null
+     */
+    public ?string $rewardGroupCode;
+
+    /**
+     * 活动特定配置参数
+     *
+     * @var array
+     */
+    public array $configParams = [];
+
+    /**
+     * 活动条件列表
+     *
+     * @var ActivityConditionDto[]
+     */
+    public array $conditions = [];
+
+    /**
+     * 用户参与状态
+     *
+     * @var ActivityParticipationDto|null
+     */
+    public ?ActivityParticipationDto $participation = null;
+
+    /**
+     * 从模型创建DTO
+     *
+     * @param ActivityConfig $model 活动配置模型
+     * @param bool $withConditions 是否包含条件
+     * @return self
+     */
+    public static function fromModel(ActivityConfig $model, bool $withConditions = false): self
+    {
+        $dto = new self();
+        $dto->id = $model->id;
+        $dto->name = $model->name;
+        $dto->type = $model->type;
+        $dto->typeName = $model->getTypeName();
+        $dto->description = $model->description ?? '';
+        $dto->startTime = $model->start_time ? $model->start_time->format('Y-m-d H:i:s') : '';
+        $dto->endTime = $model->end_time ? $model->end_time->format('Y-m-d H:i:s') : '';
+        $dto->status = $model->status;
+        $dto->statusName = $model->getStatusName();
+        $dto->displayOrder = $model->display_order;
+        $dto->icon = $model->icon;
+        $dto->banner = $model->banner;
+        $dto->rewardGroupId = $model->reward_group_id;
+        $dto->rewardGroupCode = $model->reward_group_code;
+        $dto->configParams = $model->config_params ?? [];
+
+        // 加载条件
+        if ($withConditions && $model->relationLoaded('conditions')) {
+            foreach ($model->conditions as $condition) {
+                $dto->conditions[] = ActivityConditionDto::fromModel($condition);
+            }
+        }
+
+        return $dto;
+    }
+
+    /**
+     * 转换为模型数据数组
+     *
+     * @return array
+     */
+    public function toModelArray(): array
+    {
+        return [
+            'id' => $this->id ?? null,
+            'name' => $this->name,
+            'type' => $this->type,
+            'description' => $this->description,
+            'start_time' => $this->startTime,
+            'end_time' => $this->endTime,
+            'status' => $this->status,
+            'display_order' => $this->displayOrder,
+            'icon' => $this->icon,
+            'banner' => $this->banner,
+            'reward_group_id' => $this->rewardGroupId,
+            'reward_group_code' => $this->rewardGroupCode,
+            'config_params' => $this->configParams,
+        ];
+    }
+}

+ 128 - 0
app/Module/Activity/Dtos/ActivityParticipationDto.php

@@ -0,0 +1,128 @@
+<?php
+
+namespace App\Module\Activity\Dtos;
+
+use App\Module\Activity\Models\ActivityParticipation;
+use UCore\Dto\BaseDto;
+
+/**
+ * 活动参与记录数据传输对象
+ */
+class ActivityParticipationDto extends BaseDto
+{
+    /**
+     * 记录ID
+     *
+     * @var int
+     */
+    public int $id;
+
+    /**
+     * 用户ID
+     *
+     * @var int
+     */
+    public int $userId;
+
+    /**
+     * 活动ID
+     *
+     * @var int
+     */
+    public int $activityId;
+
+    /**
+     * 参与时间
+     *
+     * @var string
+     */
+    public string $participateTime;
+
+    /**
+     * 奖励状态
+     *
+     * @var int
+     */
+    public int $rewardStatus;
+
+    /**
+     * 奖励状态名称
+     *
+     * @var string
+     */
+    public string $rewardStatusName;
+
+    /**
+     * 完成状态
+     *
+     * @var int
+     */
+    public int $completionStatus;
+
+    /**
+     * 完成状态名称
+     *
+     * @var string
+     */
+    public string $completionStatusName;
+
+    /**
+     * 完成时间
+     *
+     * @var string|null
+     */
+    public ?string $completionTime;
+
+    /**
+     * 用户活动数据
+     *
+     * @var UserActivityDataDto|null
+     */
+    public ?UserActivityDataDto $userData = null;
+
+    /**
+     * 从模型创建DTO
+     *
+     * @param ActivityParticipation $model 活动参与记录模型
+     * @param bool $withUserData 是否包含用户数据
+     * @return self
+     */
+    public static function fromModel(ActivityParticipation $model, bool $withUserData = false): self
+    {
+        $dto = new self();
+        $dto->id = $model->id;
+        $dto->userId = $model->user_id;
+        $dto->activityId = $model->activity_id;
+        $dto->participateTime = $model->participate_time ? $model->participate_time->format('Y-m-d H:i:s') : '';
+        $dto->rewardStatus = $model->reward_status;
+        $dto->rewardStatusName = $model->getRewardStatusName();
+        $dto->completionStatus = $model->completion_status;
+        $dto->completionStatusName = $model->getCompletionStatusName();
+        $dto->completionTime = $model->completion_time ? $model->completion_time->format('Y-m-d H:i:s') : null;
+
+        // 加载用户数据
+        if ($withUserData && $model->relationLoaded('userData')) {
+            $dto->userData = UserActivityDataDto::fromModel($model->userData);
+        }
+
+        return $dto;
+    }
+
+    /**
+     * 转换为模型数据数组
+     *
+     * @return array
+     */
+    public function toModelArray(): array
+    {
+        return [
+            'id' => $this->id ?? null,
+            'user_id' => $this->userId,
+            'activity_id' => $this->activityId,
+            'participate_time' => $this->participateTime,
+            'reward_status' => $this->rewardStatus,
+            'completion_status' => $this->completionStatus,
+            'completion_time' => $this->completionTime,
+        ];
+    }
+}

+ 93 - 0
app/Module/Activity/Dtos/ActivityRewardDto.php

@@ -0,0 +1,93 @@
+<?php
+
+namespace App\Module\Activity\Dtos;
+
+use UCore\Dto\BaseDto;
+
+/**
+ * 活动奖励数据传输对象
+ */
+class ActivityRewardDto extends BaseDto
+{
+    /**
+     * 奖励组ID
+     *
+     * @var int|null
+     */
+    public ?int $rewardGroupId;
+
+    /**
+     * 奖励组编码
+     *
+     * @var string|null
+     */
+    public ?string $rewardGroupCode;
+
+    /**
+     * 奖励组名称
+     *
+     * @var string|null
+     */
+    public ?string $rewardGroupName;
+
+    /**
+     * 奖励组描述
+     *
+     * @var string|null
+     */
+    public ?string $rewardGroupDescription;
+
+    /**
+     * 奖励项列表
+     *
+     * @var array
+     */
+    public array $rewardItems = [];
+
+    /**
+     * 创建一个新的活动奖励DTO实例
+     *
+     * @param int|null $rewardGroupId 奖励组ID
+     * @param string|null $rewardGroupCode 奖励组编码
+     * @param string|null $rewardGroupName 奖励组名称
+     * @param string|null $rewardGroupDescription 奖励组描述
+     * @return self
+     */
+    public static function create(
+        ?int $rewardGroupId = null,
+        ?string $rewardGroupCode = null,
+        ?string $rewardGroupName = null,
+        ?string $rewardGroupDescription = null
+    ): self {
+        $dto = new self();
+        $dto->rewardGroupId = $rewardGroupId;
+        $dto->rewardGroupCode = $rewardGroupCode;
+        $dto->rewardGroupName = $rewardGroupName;
+        $dto->rewardGroupDescription = $rewardGroupDescription;
+        return $dto;
+    }
+
+    /**
+     * 添加奖励项
+     *
+     * @param array $item 奖励项数据
+     * @return self
+     */
+    public function addRewardItem(array $item): self
+    {
+        $this->rewardItems[] = $item;
+        return $this;
+    }
+
+    /**
+     * 设置奖励项列表
+     *
+     * @param array $items 奖励项列表
+     * @return self
+     */
+    public function setRewardItems(array $items): self
+    {
+        $this->rewardItems = $items;
+        return $this;
+    }
+}

+ 90 - 0
app/Module/Activity/Dtos/UserActivityDataDto.php

@@ -0,0 +1,90 @@
+<?php
+
+namespace App\Module\Activity\Dtos;
+
+use App\Module\Activity\Models\UserActivityData;
+use UCore\Dto\BaseDto;
+
+/**
+ * 用户活动数据传输对象
+ */
+class UserActivityDataDto extends BaseDto
+{
+    /**
+     * 记录ID
+     *
+     * @var int
+     */
+    public int $id;
+
+    /**
+     * 用户ID
+     *
+     * @var int
+     */
+    public int $userId;
+
+    /**
+     * 活动ID
+     *
+     * @var int
+     */
+    public int $activityId;
+
+    /**
+     * 活动进度
+     *
+     * @var int
+     */
+    public int $progress;
+
+    /**
+     * 详细进度数据
+     *
+     * @var array
+     */
+    public array $progressData = [];
+
+    /**
+     * 最后更新时间
+     *
+     * @var string
+     */
+    public string $lastUpdate;
+
+    /**
+     * 从模型创建DTO
+     *
+     * @param UserActivityData $model 用户活动数据模型
+     * @return self
+     */
+    public static function fromModel(UserActivityData $model): self
+    {
+        $dto = new self();
+        $dto->id = $model->id;
+        $dto->userId = $model->user_id;
+        $dto->activityId = $model->activity_id;
+        $dto->progress = $model->progress;
+        $dto->progressData = $model->progress_data ?? [];
+        $dto->lastUpdate = $model->last_update ? $model->last_update->format('Y-m-d H:i:s') : '';
+
+        return $dto;
+    }
+
+    /**
+     * 转换为模型数据数组
+     *
+     * @return array
+     */
+    public function toModelArray(): array
+    {
+        return [
+            'id' => $this->id ?? null,
+            'user_id' => $this->userId,
+            'activity_id' => $this->activityId,
+            'progress' => $this->progress,
+            'progress_data' => $this->progressData,
+            'last_update' => $this->lastUpdate,
+        ];
+    }
+}

+ 66 - 0
app/Module/Activity/Enums/ACTIVITY_STATUS.php

@@ -0,0 +1,66 @@
+<?php
+
+namespace App\Module\Activity\Enums;
+
+/**
+ * 活动状态枚举
+ */
+class ACTIVITY_STATUS
+{
+    /**
+     * 未开始
+     */
+    const NOT_STARTED = 0;
+
+    /**
+     * 进行中
+     */
+    const IN_PROGRESS = 1;
+
+    /**
+     * 已结束
+     */
+    const ENDED = 2;
+
+    /**
+     * 已关闭
+     */
+    const CLOSED = 3;
+
+    /**
+     * 获取所有活动状态
+     *
+     * @return array
+     */
+    public static function getAll(): array
+    {
+        return [
+            self::NOT_STARTED => '未开始',
+            self::IN_PROGRESS => '进行中',
+            self::ENDED => '已结束',
+            self::CLOSED => '已关闭',
+        ];
+    }
+
+    /**
+     * 获取活动状态名称
+     *
+     * @param int $status
+     * @return string
+     */
+    public static function getName(int $status): string
+    {
+        return self::getAll()[$status] ?? '未知状态';
+    }
+
+    /**
+     * 检查活动状态是否有效
+     *
+     * @param int $status
+     * @return bool
+     */
+    public static function isValid(int $status): bool
+    {
+        return isset(self::getAll()[$status]);
+    }
+}

+ 72 - 0
app/Module/Activity/Enums/ACTIVITY_TYPE.php

@@ -0,0 +1,72 @@
+<?php
+
+namespace App\Module\Activity\Enums;
+
+/**
+ * 活动类型枚举
+ */
+class ACTIVITY_TYPE
+{
+    /**
+     * 礼包活动
+     */
+    const GIFT_PACKAGE = 1;
+
+    /**
+     * 限时活动
+     */
+    const TIME_LIMITED = 2;
+
+    /**
+     * 任务活动
+     */
+    const TASK = 3;
+
+    /**
+     * 签到活动
+     */
+    const SIGN_IN = 4;
+
+    /**
+     * 节日活动
+     */
+    const FESTIVAL = 5;
+
+    /**
+     * 获取所有活动类型
+     *
+     * @return array
+     */
+    public static function getAll(): array
+    {
+        return [
+            self::GIFT_PACKAGE => '礼包活动',
+            self::TIME_LIMITED => '限时活动',
+            self::TASK => '任务活动',
+            self::SIGN_IN => '签到活动',
+            self::FESTIVAL => '节日活动',
+        ];
+    }
+
+    /**
+     * 获取活动类型名称
+     *
+     * @param int $type
+     * @return string
+     */
+    public static function getName(int $type): string
+    {
+        return self::getAll()[$type] ?? '未知活动类型';
+    }
+
+    /**
+     * 检查活动类型是否有效
+     *
+     * @param int $type
+     * @return bool
+     */
+    public static function isValid(int $type): bool
+    {
+        return isset(self::getAll()[$type]);
+    }
+}

+ 78 - 0
app/Module/Activity/Enums/CONDITION_TYPE.php

@@ -0,0 +1,78 @@
+<?php
+
+namespace App\Module\Activity\Enums;
+
+/**
+ * 条件类型枚举
+ */
+class CONDITION_TYPE
+{
+    /**
+     * 等级要求
+     */
+    const LEVEL_REQUIREMENT = 1;
+
+    /**
+     * 道具要求
+     */
+    const ITEM_REQUIREMENT = 2;
+
+    /**
+     * 时间要求
+     */
+    const TIME_REQUIREMENT = 3;
+
+    /**
+     * 任务要求
+     */
+    const TASK_REQUIREMENT = 4;
+
+    /**
+     * 农场要求
+     */
+    const FARM_REQUIREMENT = 5;
+
+    /**
+     * 宠物要求
+     */
+    const PET_REQUIREMENT = 6;
+
+    /**
+     * 获取所有条件类型
+     *
+     * @return array
+     */
+    public static function getAll(): array
+    {
+        return [
+            self::LEVEL_REQUIREMENT => '等级要求',
+            self::ITEM_REQUIREMENT => '道具要求',
+            self::TIME_REQUIREMENT => '时间要求',
+            self::TASK_REQUIREMENT => '任务要求',
+            self::FARM_REQUIREMENT => '农场要求',
+            self::PET_REQUIREMENT => '宠物要求',
+        ];
+    }
+
+    /**
+     * 获取条件类型名称
+     *
+     * @param int $type
+     * @return string
+     */
+    public static function getName(int $type): string
+    {
+        return self::getAll()[$type] ?? '未知条件类型';
+    }
+
+    /**
+     * 检查条件类型是否有效
+     *
+     * @param int $type
+     * @return bool
+     */
+    public static function isValid(int $type): bool
+    {
+        return isset(self::getAll()[$type]);
+    }
+}

+ 60 - 0
app/Module/Activity/Enums/PARTICIPATION_STATUS.php

@@ -0,0 +1,60 @@
+<?php
+
+namespace App\Module\Activity\Enums;
+
+/**
+ * 参与状态枚举
+ */
+class PARTICIPATION_STATUS
+{
+    /**
+     * 进行中
+     */
+    const IN_PROGRESS = 0;
+
+    /**
+     * 已完成
+     */
+    const COMPLETED = 1;
+
+    /**
+     * 已失败
+     */
+    const FAILED = 2;
+
+    /**
+     * 获取所有参与状态
+     *
+     * @return array
+     */
+    public static function getAll(): array
+    {
+        return [
+            self::IN_PROGRESS => '进行中',
+            self::COMPLETED => '已完成',
+            self::FAILED => '已失败',
+        ];
+    }
+
+    /**
+     * 获取参与状态名称
+     *
+     * @param int $status
+     * @return string
+     */
+    public static function getName(int $status): string
+    {
+        return self::getAll()[$status] ?? '未知状态';
+    }
+
+    /**
+     * 检查参与状态是否有效
+     *
+     * @param int $status
+     * @return bool
+     */
+    public static function isValid(int $status): bool
+    {
+        return isset(self::getAll()[$status]);
+    }
+}

+ 60 - 0
app/Module/Activity/Enums/REWARD_STATUS.php

@@ -0,0 +1,60 @@
+<?php
+
+namespace App\Module\Activity\Enums;
+
+/**
+ * 奖励状态枚举
+ */
+class REWARD_STATUS
+{
+    /**
+     * 未领取
+     */
+    const NOT_CLAIMED = 0;
+
+    /**
+     * 已领取
+     */
+    const CLAIMED = 1;
+
+    /**
+     * 已过期
+     */
+    const EXPIRED = 2;
+
+    /**
+     * 获取所有奖励状态
+     *
+     * @return array
+     */
+    public static function getAll(): array
+    {
+        return [
+            self::NOT_CLAIMED => '未领取',
+            self::CLAIMED => '已领取',
+            self::EXPIRED => '已过期',
+        ];
+    }
+
+    /**
+     * 获取奖励状态名称
+     *
+     * @param int $status
+     * @return string
+     */
+    public static function getName(int $status): string
+    {
+        return self::getAll()[$status] ?? '未知状态';
+    }
+
+    /**
+     * 检查奖励状态是否有效
+     *
+     * @param int $status
+     * @return bool
+     */
+    public static function isValid(int $status): bool
+    {
+        return isset(self::getAll()[$status]);
+    }
+}

+ 41 - 0
app/Module/Activity/Events/ActivityCompletedEvent.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Module\Activity\Events;
+
+use Illuminate\Broadcasting\InteractsWithSockets;
+use Illuminate\Foundation\Events\Dispatchable;
+use Illuminate\Queue\SerializesModels;
+
+/**
+ * 活动完成事件
+ */
+class ActivityCompletedEvent
+{
+    use Dispatchable, InteractsWithSockets, SerializesModels;
+
+    /**
+     * 用户ID
+     *
+     * @var int
+     */
+    public int $userId;
+
+    /**
+     * 活动ID
+     *
+     * @var int
+     */
+    public int $activityId;
+
+    /**
+     * 创建一个新的事件实例
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     */
+    public function __construct(int $userId, int $activityId)
+    {
+        $this->userId = $userId;
+        $this->activityId = $activityId;
+    }
+}

+ 42 - 0
app/Module/Activity/Events/ActivityCreatedEvent.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace App\Module\Activity\Events;
+
+use App\Module\Activity\Dtos\ActivityConfigDto;
+use Illuminate\Broadcasting\InteractsWithSockets;
+use Illuminate\Foundation\Events\Dispatchable;
+use Illuminate\Queue\SerializesModels;
+
+/**
+ * 活动创建事件
+ */
+class ActivityCreatedEvent
+{
+    use Dispatchable, InteractsWithSockets, SerializesModels;
+
+    /**
+     * 活动ID
+     *
+     * @var int
+     */
+    public int $activityId;
+
+    /**
+     * 活动配置DTO
+     *
+     * @var ActivityConfigDto
+     */
+    public ActivityConfigDto $activity;
+
+    /**
+     * 创建一个新的事件实例
+     *
+     * @param int $activityId 活动ID
+     * @param ActivityConfigDto $activity 活动配置DTO
+     */
+    public function __construct(int $activityId, ActivityConfigDto $activity)
+    {
+        $this->activityId = $activityId;
+        $this->activity = $activity;
+    }
+}

+ 59 - 0
app/Module/Activity/Events/ActivityProgressUpdatedEvent.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace App\Module\Activity\Events;
+
+use Illuminate\Broadcasting\InteractsWithSockets;
+use Illuminate\Foundation\Events\Dispatchable;
+use Illuminate\Queue\SerializesModels;
+
+/**
+ * 活动进度更新事件
+ */
+class ActivityProgressUpdatedEvent
+{
+    use Dispatchable, InteractsWithSockets, SerializesModels;
+
+    /**
+     * 用户ID
+     *
+     * @var int
+     */
+    public int $userId;
+
+    /**
+     * 活动ID
+     *
+     * @var int
+     */
+    public int $activityId;
+
+    /**
+     * 旧进度
+     *
+     * @var int
+     */
+    public int $oldProgress;
+
+    /**
+     * 新进度
+     *
+     * @var int
+     */
+    public int $newProgress;
+
+    /**
+     * 创建一个新的事件实例
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @param int $oldProgress 旧进度
+     * @param int $newProgress 新进度
+     */
+    public function __construct(int $userId, int $activityId, int $oldProgress, int $newProgress)
+    {
+        $this->userId = $userId;
+        $this->activityId = $activityId;
+        $this->oldProgress = $oldProgress;
+        $this->newProgress = $newProgress;
+    }
+}

+ 50 - 0
app/Module/Activity/Events/ActivityRewardClaimedEvent.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Module\Activity\Events;
+
+use Illuminate\Broadcasting\InteractsWithSockets;
+use Illuminate\Foundation\Events\Dispatchable;
+use Illuminate\Queue\SerializesModels;
+
+/**
+ * 活动奖励领取事件
+ */
+class ActivityRewardClaimedEvent
+{
+    use Dispatchable, InteractsWithSockets, SerializesModels;
+
+    /**
+     * 用户ID
+     *
+     * @var int
+     */
+    public int $userId;
+
+    /**
+     * 活动ID
+     *
+     * @var int
+     */
+    public int $activityId;
+
+    /**
+     * 奖励结果
+     *
+     * @var array
+     */
+    public array $rewardResult;
+
+    /**
+     * 创建一个新的事件实例
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @param array $rewardResult 奖励结果
+     */
+    public function __construct(int $userId, int $activityId, array $rewardResult)
+    {
+        $this->userId = $userId;
+        $this->activityId = $activityId;
+        $this->rewardResult = $rewardResult;
+    }
+}

+ 50 - 0
app/Module/Activity/Events/ActivityStatusChangedEvent.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Module\Activity\Events;
+
+use Illuminate\Broadcasting\InteractsWithSockets;
+use Illuminate\Foundation\Events\Dispatchable;
+use Illuminate\Queue\SerializesModels;
+
+/**
+ * 活动状态变更事件
+ */
+class ActivityStatusChangedEvent
+{
+    use Dispatchable, InteractsWithSockets, SerializesModels;
+
+    /**
+     * 活动ID
+     *
+     * @var int
+     */
+    public int $activityId;
+
+    /**
+     * 旧状态
+     *
+     * @var int
+     */
+    public int $oldStatus;
+
+    /**
+     * 新状态
+     *
+     * @var int
+     */
+    public int $newStatus;
+
+    /**
+     * 创建一个新的事件实例
+     *
+     * @param int $activityId 活动ID
+     * @param int $oldStatus 旧状态
+     * @param int $newStatus 新状态
+     */
+    public function __construct(int $activityId, int $oldStatus, int $newStatus)
+    {
+        $this->activityId = $activityId;
+        $this->oldStatus = $oldStatus;
+        $this->newStatus = $newStatus;
+    }
+}

+ 41 - 0
app/Module/Activity/Events/UserParticipatedEvent.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Module\Activity\Events;
+
+use Illuminate\Broadcasting\InteractsWithSockets;
+use Illuminate\Foundation\Events\Dispatchable;
+use Illuminate\Queue\SerializesModels;
+
+/**
+ * 用户参与活动事件
+ */
+class UserParticipatedEvent
+{
+    use Dispatchable, InteractsWithSockets, SerializesModels;
+
+    /**
+     * 用户ID
+     *
+     * @var int
+     */
+    public int $userId;
+
+    /**
+     * 活动ID
+     *
+     * @var int
+     */
+    public int $activityId;
+
+    /**
+     * 创建一个新的事件实例
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     */
+    public function __construct(int $userId, int $activityId)
+    {
+        $this->userId = $userId;
+        $this->activityId = $activityId;
+    }
+}

+ 63 - 0
app/Module/Activity/Listeners/ActivityCompletedListener.php

@@ -0,0 +1,63 @@
+<?php
+
+namespace App\Module\Activity\Listeners;
+
+use App\Module\Activity\Events\ActivityCompletedEvent;
+use Illuminate\Support\Facades\Log;
+
+/**
+ * 活动完成监听器
+ */
+class ActivityCompletedListener
+{
+    /**
+     * 处理事件
+     *
+     * @param ActivityCompletedEvent $event
+     * @return void
+     */
+    public function handle(ActivityCompletedEvent $event): void
+    {
+        Log::info('活动完成', [
+            'user_id' => $event->userId,
+            'activity_id' => $event->activityId
+        ]);
+
+        // 可以在这里执行活动完成时的操作
+        // 例如:发送完成通知、更新用户成就等
+        $this->sendCompletionNotification($event->userId, $event->activityId);
+        $this->updateUserAchievements($event->userId);
+    }
+
+    /**
+     * 发送完成通知
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return void
+     */
+    private function sendCompletionNotification(int $userId, int $activityId): void
+    {
+        // 这里可以实现发送完成通知的逻辑
+        // 例如:调用通知服务发送消息
+        Log::info('发送活动完成通知', [
+            'user_id' => $userId,
+            'activity_id' => $activityId
+        ]);
+    }
+
+    /**
+     * 更新用户成就
+     *
+     * @param int $userId 用户ID
+     * @return void
+     */
+    private function updateUserAchievements(int $userId): void
+    {
+        // 这里可以实现更新用户成就的逻辑
+        // 例如:增加用户完成活动次数、检查是否达成相关成就等
+        Log::info('更新用户成就', [
+            'user_id' => $userId
+        ]);
+    }
+}

+ 61 - 0
app/Module/Activity/Listeners/ActivityProgressListener.php

@@ -0,0 +1,61 @@
+<?php
+
+namespace App\Module\Activity\Listeners;
+
+use App\Module\Activity\Events\ActivityProgressUpdatedEvent;
+use Illuminate\Support\Facades\Log;
+
+/**
+ * 活动进度监听器
+ */
+class ActivityProgressListener
+{
+    /**
+     * 处理事件
+     *
+     * @param ActivityProgressUpdatedEvent $event
+     * @return void
+     */
+    public function handle(ActivityProgressUpdatedEvent $event): void
+    {
+        Log::info('活动进度更新', [
+            'user_id' => $event->userId,
+            'activity_id' => $event->activityId,
+            'old_progress' => $event->oldProgress,
+            'new_progress' => $event->newProgress
+        ]);
+
+        // 可以在这里执行活动进度更新时的操作
+        // 例如:发送进度更新通知、检查是否达到特定进度点等
+        $this->checkProgressMilestones($event->userId, $event->activityId, $event->newProgress);
+    }
+
+    /**
+     * 检查进度里程碑
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @param int $progress 当前进度
+     * @return void
+     */
+    private function checkProgressMilestones(int $userId, int $activityId, int $progress): void
+    {
+        // 这里可以实现检查进度里程碑的逻辑
+        // 例如:当进度达到特定值时,发送鼓励通知或发放阶段性奖励
+        $milestones = [25, 50, 75, 100]; // 示例里程碑点
+
+        foreach ($milestones as $milestone) {
+            if ($progress >= $milestone) {
+                Log::info('达到进度里程碑', [
+                    'user_id' => $userId,
+                    'activity_id' => $activityId,
+                    'milestone' => $milestone,
+                    'progress' => $progress
+                ]);
+
+                // 可以在这里执行达到里程碑时的操作
+                // 例如:发送鼓励通知
+            }
+        }
+    }
+}

+ 91 - 0
app/Module/Activity/Listeners/ActivityStatusChangeListener.php

@@ -0,0 +1,91 @@
+<?php
+
+namespace App\Module\Activity\Listeners;
+
+use App\Module\Activity\Enums\ACTIVITY_STATUS;
+use App\Module\Activity\Events\ActivityStatusChangedEvent;
+use Illuminate\Support\Facades\Log;
+
+/**
+ * 活动状态变更监听器
+ */
+class ActivityStatusChangeListener
+{
+    /**
+     * 处理事件
+     *
+     * @param ActivityStatusChangedEvent $event
+     * @return void
+     */
+    public function handle(ActivityStatusChangedEvent $event): void
+    {
+        Log::info('活动状态变更', [
+            'activity_id' => $event->activityId,
+            'old_status' => $event->oldStatus,
+            'new_status' => $event->newStatus
+        ]);
+
+        // 根据不同的状态变更执行不同的操作
+        switch ($event->newStatus) {
+            case ACTIVITY_STATUS::IN_PROGRESS:
+                // 活动开始
+                $this->handleActivityStart($event->activityId);
+                break;
+
+            case ACTIVITY_STATUS::ENDED:
+                // 活动结束
+                $this->handleActivityEnd($event->activityId);
+                break;
+
+            case ACTIVITY_STATUS::CLOSED:
+                // 活动关闭
+                $this->handleActivityClose($event->activityId);
+                break;
+        }
+    }
+
+    /**
+     * 处理活动开始
+     *
+     * @param int $activityId 活动ID
+     * @return void
+     */
+    private function handleActivityStart(int $activityId): void
+    {
+        // 可以在这里执行活动开始时的操作
+        // 例如:发送活动开始通知、更新活动相关数据等
+        Log::info('活动开始', [
+            'activity_id' => $activityId
+        ]);
+    }
+
+    /**
+     * 处理活动结束
+     *
+     * @param int $activityId 活动ID
+     * @return void
+     */
+    private function handleActivityEnd(int $activityId): void
+    {
+        // 可以在这里执行活动结束时的操作
+        // 例如:发送活动结束通知、处理未完成的参与记录等
+        Log::info('活动结束', [
+            'activity_id' => $activityId
+        ]);
+    }
+
+    /**
+     * 处理活动关闭
+     *
+     * @param int $activityId 活动ID
+     * @return void
+     */
+    private function handleActivityClose(int $activityId): void
+    {
+        // 可以在这里执行活动关闭时的操作
+        // 例如:清理活动相关数据、归档活动记录等
+        Log::info('活动关闭', [
+            'activity_id' => $activityId
+        ]);
+    }
+}

+ 68 - 0
app/Module/Activity/Listeners/RewardDistributionListener.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace App\Module\Activity\Listeners;
+
+use App\Module\Activity\Events\ActivityRewardClaimedEvent;
+use Illuminate\Support\Facades\Log;
+
+/**
+ * 奖励发放监听器
+ */
+class RewardDistributionListener
+{
+    /**
+     * 处理事件
+     *
+     * @param ActivityRewardClaimedEvent $event
+     * @return void
+     */
+    public function handle(ActivityRewardClaimedEvent $event): void
+    {
+        Log::info('活动奖励领取', [
+            'user_id' => $event->userId,
+            'activity_id' => $event->activityId,
+            'reward_result' => $event->rewardResult
+        ]);
+
+        // 可以在这里执行奖励领取时的操作
+        // 例如:发送奖励通知、更新用户奖励统计等
+        $this->sendRewardNotification($event->userId, $event->activityId, $event->rewardResult);
+        $this->updateUserRewardStatistics($event->userId, $event->rewardResult);
+    }
+
+    /**
+     * 发送奖励通知
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @param array $rewardResult 奖励结果
+     * @return void
+     */
+    private function sendRewardNotification(int $userId, int $activityId, array $rewardResult): void
+    {
+        // 这里可以实现发送奖励通知的逻辑
+        // 例如:调用通知服务发送消息
+        Log::info('发送活动奖励通知', [
+            'user_id' => $userId,
+            'activity_id' => $activityId,
+            'reward_result' => $rewardResult
+        ]);
+    }
+
+    /**
+     * 更新用户奖励统计
+     *
+     * @param int $userId 用户ID
+     * @param array $rewardResult 奖励结果
+     * @return void
+     */
+    private function updateUserRewardStatistics(int $userId, array $rewardResult): void
+    {
+        // 这里可以实现更新用户奖励统计的逻辑
+        // 例如:增加用户获得奖励次数、记录奖励总量等
+        Log::info('更新用户奖励统计', [
+            'user_id' => $userId,
+            'reward_result' => $rewardResult
+        ]);
+    }
+}

+ 63 - 0
app/Module/Activity/Listeners/UserParticipationListener.php

@@ -0,0 +1,63 @@
+<?php
+
+namespace App\Module\Activity\Listeners;
+
+use App\Module\Activity\Events\UserParticipatedEvent;
+use Illuminate\Support\Facades\Log;
+
+/**
+ * 用户参与监听器
+ */
+class UserParticipationListener
+{
+    /**
+     * 处理事件
+     *
+     * @param UserParticipatedEvent $event
+     * @return void
+     */
+    public function handle(UserParticipatedEvent $event): void
+    {
+        Log::info('用户参与活动', [
+            'user_id' => $event->userId,
+            'activity_id' => $event->activityId
+        ]);
+
+        // 可以在这里执行用户参与活动时的操作
+        // 例如:发送参与通知、更新用户统计数据等
+        $this->sendParticipationNotification($event->userId, $event->activityId);
+        $this->updateUserStatistics($event->userId);
+    }
+
+    /**
+     * 发送参与通知
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return void
+     */
+    private function sendParticipationNotification(int $userId, int $activityId): void
+    {
+        // 这里可以实现发送参与通知的逻辑
+        // 例如:调用通知服务发送消息
+        Log::info('发送活动参与通知', [
+            'user_id' => $userId,
+            'activity_id' => $activityId
+        ]);
+    }
+
+    /**
+     * 更新用户统计数据
+     *
+     * @param int $userId 用户ID
+     * @return void
+     */
+    private function updateUserStatistics(int $userId): void
+    {
+        // 这里可以实现更新用户统计数据的逻辑
+        // 例如:增加用户参与活动次数
+        Log::info('更新用户活动统计数据', [
+            'user_id' => $userId
+        ]);
+    }
+}

+ 421 - 0
app/Module/Activity/Logics/ActivityLogic.php

@@ -0,0 +1,421 @@
+<?php
+
+namespace App\Module\Activity\Logics;
+
+use App\Module\Activity\Dtos\ActivityConfigDto;
+use App\Module\Activity\Dtos\ActivityParticipationDto;
+use App\Module\Activity\Enums\ACTIVITY_STATUS;
+use App\Module\Activity\Enums\PARTICIPATION_STATUS;
+use App\Module\Activity\Enums\REWARD_STATUS;
+use App\Module\Activity\Events\ActivityCompletedEvent;
+use App\Module\Activity\Events\ActivityProgressUpdatedEvent;
+use App\Module\Activity\Events\ActivityRewardClaimedEvent;
+use App\Module\Activity\Events\UserParticipatedEvent;
+use App\Module\Activity\Models\ActivityConfig;
+use App\Module\Activity\Models\ActivityCondition;
+use App\Module\Activity\Models\ActivityParticipation;
+use App\Module\Activity\Models\UserActivityData;
+use Carbon\Carbon;
+use Exception;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Event;
+use Illuminate\Support\Facades\Log;
+
+/**
+ * 活动逻辑类
+ */
+class ActivityLogic
+{
+    /**
+     * 获取活动详情
+     *
+     * @param int $activityId 活动ID
+     * @param bool $withConditions 是否包含条件
+     * @return ActivityConfigDto|null
+     */
+    public function getActivityDetail(int $activityId, bool $withConditions = false): ?ActivityConfigDto
+    {
+        $query = ActivityConfig::query();
+        
+        if ($withConditions) {
+            $query->with('conditions');
+        }
+        
+        $activity = $query->find($activityId);
+        
+        if (!$activity) {
+            return null;
+        }
+        
+        return ActivityConfigDto::fromModel($activity, $withConditions);
+    }
+
+    /**
+     * 获取用户可参与的活动列表
+     *
+     * @param int $userId 用户ID
+     * @return array
+     */
+    public function getUserAvailableActivities(int $userId): array
+    {
+        // 获取进行中的活动
+        $activities = ActivityConfig::where('status', ACTIVITY_STATUS::IN_PROGRESS)
+            ->where('start_time', '<=', now())
+            ->where('end_time', '>=', now())
+            ->orderBy('display_order', 'desc')
+            ->get();
+        
+        $result = [];
+        
+        foreach ($activities as $activity) {
+            // 检查用户是否已参与且完成或失败
+            $participation = ActivityParticipation::where('user_id', $userId)
+                ->where('activity_id', $activity->id)
+                ->whereIn('completion_status', [PARTICIPATION_STATUS::COMPLETED, PARTICIPATION_STATUS::FAILED])
+                ->first();
+            
+            // 如果用户已完成或失败,则跳过
+            if ($participation) {
+                continue;
+            }
+            
+            // 检查参与条件
+            if ($this->checkParticipationConditions($userId, $activity->id)) {
+                $result[] = ActivityConfigDto::fromModel($activity);
+            }
+        }
+        
+        return $result;
+    }
+
+    /**
+     * 参与活动
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return ActivityParticipationDto
+     * @throws Exception
+     */
+    public function participateActivity(int $userId, int $activityId): ActivityParticipationDto
+    {
+        // 获取活动信息
+        $activity = ActivityConfig::findOrFail($activityId);
+        
+        // 检查活动状态
+        if ($activity->status !== ACTIVITY_STATUS::IN_PROGRESS) {
+            throw new Exception('活动未开始或已结束');
+        }
+        
+        // 检查活动时间
+        $now = now();
+        if ($activity->start_time > $now || $activity->end_time < $now) {
+            throw new Exception('不在活动时间范围内');
+        }
+        
+        // 检查用户是否已参与且完成或失败
+        $existingParticipation = ActivityParticipation::where('user_id', $userId)
+            ->where('activity_id', $activityId)
+            ->whereIn('completion_status', [PARTICIPATION_STATUS::COMPLETED, PARTICIPATION_STATUS::FAILED])
+            ->first();
+        
+        if ($existingParticipation) {
+            throw new Exception('您已完成或失败此活动,无法再次参与');
+        }
+        
+        // 检查参与条件
+        if (!$this->checkParticipationConditions($userId, $activityId)) {
+            throw new Exception('不满足活动参与条件');
+        }
+        
+        // 开始事务
+        DB::beginTransaction();
+        
+        try {
+            // 查找或创建参与记录
+            $participation = ActivityParticipation::firstOrNew([
+                'user_id' => $userId,
+                'activity_id' => $activityId,
+            ]);
+            
+            $isNewParticipation = !$participation->exists;
+            
+            // 设置参与记录属性
+            $participation->participate_time = $now;
+            $participation->reward_status = REWARD_STATUS::NOT_CLAIMED;
+            $participation->completion_status = PARTICIPATION_STATUS::IN_PROGRESS;
+            $participation->save();
+            
+            // 创建或更新用户活动数据
+            $userData = UserActivityData::firstOrNew([
+                'user_id' => $userId,
+                'activity_id' => $activityId,
+            ]);
+            
+            if (!$userData->exists) {
+                $userData->progress = 0;
+                $userData->progress_data = [];
+            }
+            
+            $userData->last_update = $now;
+            $userData->save();
+            
+            // 提交事务
+            DB::commit();
+            
+            // 如果是新参与,触发用户参与活动事件
+            if ($isNewParticipation) {
+                Event::dispatch(new UserParticipatedEvent($userId, $activityId));
+            }
+            
+            // 返回参与记录DTO
+            return ActivityParticipationDto::fromModel($participation);
+        } catch (Exception $e) {
+            // 回滚事务
+            DB::rollBack();
+            throw $e;
+        }
+    }
+
+    /**
+     * 更新活动进度
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @param int $progress 进度值
+     * @param array|null $progressData 进度数据
+     * @return bool
+     * @throws Exception
+     */
+    public function updateActivityProgress(int $userId, int $activityId, int $progress, ?array $progressData = null): bool
+    {
+        // 获取用户参与记录
+        $participation = ActivityParticipation::where('user_id', $userId)
+            ->where('activity_id', $activityId)
+            ->first();
+        
+        if (!$participation) {
+            throw new Exception('用户未参与此活动');
+        }
+        
+        if ($participation->completion_status !== PARTICIPATION_STATUS::IN_PROGRESS) {
+            throw new Exception('活动已完成或失败,无法更新进度');
+        }
+        
+        // 开始事务
+        DB::beginTransaction();
+        
+        try {
+            // 更新用户活动数据
+            $userData = UserActivityData::firstOrNew([
+                'user_id' => $userId,
+                'activity_id' => $activityId,
+            ]);
+            
+            $oldProgress = $userData->progress;
+            
+            $userData->progress = $progress;
+            if ($progressData !== null) {
+                $userData->progress_data = $progressData;
+            }
+            $userData->last_update = now();
+            $userData->save();
+            
+            // 检查是否满足完成条件
+            $isCompleted = $this->checkCompletionConditions($userId, $activityId);
+            
+            if ($isCompleted) {
+                // 更新参与记录为已完成
+                $participation->completion_status = PARTICIPATION_STATUS::COMPLETED;
+                $participation->completion_time = now();
+                $participation->save();
+                
+                // 触发活动完成事件
+                Event::dispatch(new ActivityCompletedEvent($userId, $activityId));
+            }
+            
+            // 提交事务
+            DB::commit();
+            
+            // 触发活动进度更新事件
+            Event::dispatch(new ActivityProgressUpdatedEvent($userId, $activityId, $oldProgress, $progress));
+            
+            return true;
+        } catch (Exception $e) {
+            // 回滚事务
+            DB::rollBack();
+            throw $e;
+        }
+    }
+
+    /**
+     * 领取活动奖励
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return bool
+     * @throws Exception
+     */
+    public function claimActivityReward(int $userId, int $activityId): bool
+    {
+        // 获取用户参与记录
+        $participation = ActivityParticipation::where('user_id', $userId)
+            ->where('activity_id', $activityId)
+            ->first();
+        
+        if (!$participation) {
+            throw new Exception('用户未参与此活动');
+        }
+        
+        if ($participation->completion_status !== PARTICIPATION_STATUS::COMPLETED) {
+            throw new Exception('活动未完成,无法领取奖励');
+        }
+        
+        if ($participation->reward_status === REWARD_STATUS::CLAIMED) {
+            throw new Exception('奖励已领取');
+        }
+        
+        // 获取活动信息
+        $activity = ActivityConfig::findOrFail($activityId);
+        
+        // 开始事务
+        DB::beginTransaction();
+        
+        try {
+            // 更新参与记录为已领取
+            $participation->reward_status = REWARD_STATUS::CLAIMED;
+            $participation->save();
+            
+            // 发放奖励
+            $rewardResult = $this->grantActivityReward($userId, $activity);
+            
+            // 提交事务
+            DB::commit();
+            
+            // 触发奖励领取事件
+            Event::dispatch(new ActivityRewardClaimedEvent($userId, $activityId, $rewardResult));
+            
+            return true;
+        } catch (Exception $e) {
+            // 回滚事务
+            DB::rollBack();
+            throw $e;
+        }
+    }
+
+    /**
+     * 检查参与条件
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return bool
+     */
+    private function checkParticipationConditions(int $userId, int $activityId): bool
+    {
+        // 获取活动的参与条件
+        $conditions = ActivityCondition::where('activity_id', $activityId)
+            ->where('is_participation_condition', true)
+            ->get();
+        
+        // 如果没有参与条件,则默认可以参与
+        if ($conditions->isEmpty()) {
+            return true;
+        }
+        
+        // 检查每个条件
+        foreach ($conditions as $condition) {
+            // 根据条件类型进行检查
+            $conditionChecker = new ConditionLogic();
+            if (!$conditionChecker->checkCondition($userId, $condition)) {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+
+    /**
+     * 检查完成条件
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return bool
+     */
+    private function checkCompletionConditions(int $userId, int $activityId): bool
+    {
+        // 获取活动的完成条件
+        $conditions = ActivityCondition::where('activity_id', $activityId)
+            ->where('is_completion_condition', true)
+            ->get();
+        
+        // 如果没有完成条件,则默认已完成
+        if ($conditions->isEmpty()) {
+            return true;
+        }
+        
+        // 检查每个条件
+        foreach ($conditions as $condition) {
+            // 根据条件类型进行检查
+            $conditionChecker = new ConditionLogic();
+            if (!$conditionChecker->checkCondition($userId, $condition)) {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+
+    /**
+     * 发放活动奖励
+     *
+     * @param int $userId 用户ID
+     * @param ActivityConfig $activity 活动配置
+     * @return array 奖励结果
+     */
+    private function grantActivityReward(int $userId, ActivityConfig $activity): array
+    {
+        $result = [
+            'success' => true,
+            'rewards' => []
+        ];
+        
+        // 如果活动配置了奖励组
+        if ($activity->reward_group_id || $activity->reward_group_code) {
+            try {
+                // 使用奖励组服务发放奖励
+                $rewardGroupId = $activity->reward_group_id;
+                $rewardGroupCode = $activity->reward_group_code;
+                
+                // 调用奖励组服务
+                $rewardService = new \App\Module\Game\Services\RewardService();
+                $rewardResult = $rewardService::grantReward(
+                    $userId,
+                    $rewardGroupId ?: $rewardGroupCode,
+                    'activity',
+                    $activity->id
+                );
+                
+                if ($rewardResult->success) {
+                    $result['rewards'] = $rewardResult->items;
+                } else {
+                    Log::error('活动奖励发放失败', [
+                        'user_id' => $userId,
+                        'activity_id' => $activity->id,
+                        'error' => $rewardResult->errorMessage
+                    ]);
+                    $result['success'] = false;
+                    $result['error'] = $rewardResult->errorMessage;
+                }
+            } catch (Exception $e) {
+                Log::error('活动奖励发放异常', [
+                    'user_id' => $userId,
+                    'activity_id' => $activity->id,
+                    'error' => $e->getMessage()
+                ]);
+                $result['success'] = false;
+                $result['error'] = $e->getMessage();
+            }
+        }
+        
+        return $result;
+    }
+}

+ 333 - 0
app/Module/Activity/Logics/ConditionLogic.php

@@ -0,0 +1,333 @@
+<?php
+
+namespace App\Module\Activity\Logics;
+
+use App\Module\Activity\Enums\CONDITION_TYPE;
+use App\Module\Activity\Models\ActivityCondition;
+use Illuminate\Support\Facades\Log;
+
+/**
+ * 条件检查逻辑类
+ */
+class ConditionLogic
+{
+    /**
+     * 检查条件是否满足
+     *
+     * @param int $userId 用户ID
+     * @param ActivityCondition $condition 条件
+     * @return bool
+     */
+    public function checkCondition(int $userId, ActivityCondition $condition): bool
+    {
+        try {
+            switch ($condition->condition_type) {
+                case CONDITION_TYPE::LEVEL_REQUIREMENT:
+                    return $this->checkLevelRequirement($userId, $condition->condition_params);
+                
+                case CONDITION_TYPE::ITEM_REQUIREMENT:
+                    return $this->checkItemRequirement($userId, $condition->condition_params);
+                
+                case CONDITION_TYPE::TIME_REQUIREMENT:
+                    return $this->checkTimeRequirement($condition->condition_params);
+                
+                case CONDITION_TYPE::TASK_REQUIREMENT:
+                    return $this->checkTaskRequirement($userId, $condition->condition_params);
+                
+                case CONDITION_TYPE::FARM_REQUIREMENT:
+                    return $this->checkFarmRequirement($userId, $condition->condition_params);
+                
+                case CONDITION_TYPE::PET_REQUIREMENT:
+                    return $this->checkPetRequirement($userId, $condition->condition_params);
+                
+                default:
+                    Log::warning('未知的条件类型', [
+                        'condition_type' => $condition->condition_type,
+                        'condition_id' => $condition->id
+                    ]);
+                    return false;
+            }
+        } catch (\Exception $e) {
+            Log::error('检查条件时发生错误', [
+                'condition_id' => $condition->id,
+                'error' => $e->getMessage()
+            ]);
+            return false;
+        }
+    }
+
+    /**
+     * 检查等级要求
+     *
+     * @param int $userId 用户ID
+     * @param array $params 条件参数
+     * @return bool
+     */
+    private function checkLevelRequirement(int $userId, array $params): bool
+    {
+        // 获取用户等级
+        $userLevel = $this->getUserLevel($userId);
+        
+        // 检查最小等级要求
+        if (isset($params['min_level']) && $userLevel < $params['min_level']) {
+            return false;
+        }
+        
+        // 检查最大等级要求
+        if (isset($params['max_level']) && $userLevel > $params['max_level']) {
+            return false;
+        }
+        
+        return true;
+    }
+
+    /**
+     * 检查物品要求
+     *
+     * @param int $userId 用户ID
+     * @param array $params 条件参数
+     * @return bool
+     */
+    private function checkItemRequirement(int $userId, array $params): bool
+    {
+        // 检查是否需要特定物品
+        if (isset($params['items']) && is_array($params['items'])) {
+            foreach ($params['items'] as $item) {
+                $itemId = $item['item_id'] ?? 0;
+                $quantity = $item['quantity'] ?? 1;
+                
+                if ($itemId > 0) {
+                    // 获取用户物品数量
+                    $userItemCount = $this->getUserItemCount($userId, $itemId);
+                    
+                    if ($userItemCount < $quantity) {
+                        return false;
+                    }
+                }
+            }
+        }
+        
+        return true;
+    }
+
+    /**
+     * 检查时间要求
+     *
+     * @param array $params 条件参数
+     * @return bool
+     */
+    private function checkTimeRequirement(array $params): bool
+    {
+        $now = now();
+        
+        // 检查开始时间
+        if (isset($params['start_time']) && $now < \Carbon\Carbon::parse($params['start_time'])) {
+            return false;
+        }
+        
+        // 检查结束时间
+        if (isset($params['end_time']) && $now > \Carbon\Carbon::parse($params['end_time'])) {
+            return false;
+        }
+        
+        // 检查星期几
+        if (isset($params['days_of_week']) && is_array($params['days_of_week'])) {
+            $currentDayOfWeek = $now->dayOfWeek;
+            if (!in_array($currentDayOfWeek, $params['days_of_week'])) {
+                return false;
+            }
+        }
+        
+        // 检查每日时间段
+        if (isset($params['daily_start_time']) && isset($params['daily_end_time'])) {
+            $dailyStartTime = \Carbon\Carbon::createFromFormat('H:i', $params['daily_start_time']);
+            $dailyEndTime = \Carbon\Carbon::createFromFormat('H:i', $params['daily_end_time']);
+            
+            $currentTime = \Carbon\Carbon::createFromFormat('H:i', $now->format('H:i'));
+            
+            if ($currentTime < $dailyStartTime || $currentTime > $dailyEndTime) {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+
+    /**
+     * 检查任务要求
+     *
+     * @param int $userId 用户ID
+     * @param array $params 条件参数
+     * @return bool
+     */
+    private function checkTaskRequirement(int $userId, array $params): bool
+    {
+        // 检查是否需要完成特定任务
+        if (isset($params['task_ids']) && is_array($params['task_ids'])) {
+            foreach ($params['task_ids'] as $taskId) {
+                // 检查用户是否完成了任务
+                if (!$this->isTaskCompleted($userId, $taskId)) {
+                    return false;
+                }
+            }
+        }
+        
+        return true;
+    }
+
+    /**
+     * 检查农场要求
+     *
+     * @param int $userId 用户ID
+     * @param array $params 条件参数
+     * @return bool
+     */
+    private function checkFarmRequirement(int $userId, array $params): bool
+    {
+        // 检查农场等级要求
+        if (isset($params['farm_level']) && $this->getFarmLevel($userId) < $params['farm_level']) {
+            return false;
+        }
+        
+        // 检查是否拥有特定作物
+        if (isset($params['crops']) && is_array($params['crops'])) {
+            foreach ($params['crops'] as $crop) {
+                $cropId = $crop['crop_id'] ?? 0;
+                $quantity = $crop['quantity'] ?? 1;
+                
+                if ($cropId > 0) {
+                    // 获取用户作物数量
+                    $userCropCount = $this->getUserCropCount($userId, $cropId);
+                    
+                    if ($userCropCount < $quantity) {
+                        return false;
+                    }
+                }
+            }
+        }
+        
+        return true;
+    }
+
+    /**
+     * 检查宠物要求
+     *
+     * @param int $userId 用户ID
+     * @param array $params 条件参数
+     * @return bool
+     */
+    private function checkPetRequirement(int $userId, array $params): bool
+    {
+        // 检查是否拥有特定宠物
+        if (isset($params['pet_type_id']) && !$this->hasPet($userId, $params['pet_type_id'])) {
+            return false;
+        }
+        
+        // 检查宠物等级要求
+        if (isset($params['pet_level']) && isset($params['pet_type_id'])) {
+            $petLevel = $this->getPetLevel($userId, $params['pet_type_id']);
+            
+            if ($petLevel < $params['pet_level']) {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+
+    /**
+     * 获取用户等级
+     *
+     * @param int $userId 用户ID
+     * @return int
+     */
+    private function getUserLevel(int $userId): int
+    {
+        // 这里应该调用用户等级服务获取用户等级
+        // 由于没有实际的用户等级服务,这里返回一个模拟值
+        return 1;
+    }
+
+    /**
+     * 获取用户物品数量
+     *
+     * @param int $userId 用户ID
+     * @param int $itemId 物品ID
+     * @return int
+     */
+    private function getUserItemCount(int $userId, int $itemId): int
+    {
+        // 这里应该调用物品服务获取用户物品数量
+        // 由于没有实际的物品服务,这里返回一个模拟值
+        return 0;
+    }
+
+    /**
+     * 检查用户是否完成了任务
+     *
+     * @param int $userId 用户ID
+     * @param int $taskId 任务ID
+     * @return bool
+     */
+    private function isTaskCompleted(int $userId, int $taskId): bool
+    {
+        // 这里应该调用任务服务检查用户是否完成了任务
+        // 由于没有实际的任务服务,这里返回一个模拟值
+        return false;
+    }
+
+    /**
+     * 获取农场等级
+     *
+     * @param int $userId 用户ID
+     * @return int
+     */
+    private function getFarmLevel(int $userId): int
+    {
+        // 这里应该调用农场服务获取农场等级
+        // 由于没有实际的农场服务,这里返回一个模拟值
+        return 1;
+    }
+
+    /**
+     * 获取用户作物数量
+     *
+     * @param int $userId 用户ID
+     * @param int $cropId 作物ID
+     * @return int
+     */
+    private function getUserCropCount(int $userId, int $cropId): int
+    {
+        // 这里应该调用农场服务获取用户作物数量
+        // 由于没有实际的农场服务,这里返回一个模拟值
+        return 0;
+    }
+
+    /**
+     * 检查用户是否拥有特定宠物
+     *
+     * @param int $userId 用户ID
+     * @param int $petTypeId 宠物类型ID
+     * @return bool
+     */
+    private function hasPet(int $userId, int $petTypeId): bool
+    {
+        // 这里应该调用宠物服务检查用户是否拥有特定宠物
+        // 由于没有实际的宠物服务,这里返回一个模拟值
+        return false;
+    }
+
+    /**
+     * 获取宠物等级
+     *
+     * @param int $userId 用户ID
+     * @param int $petTypeId 宠物类型ID
+     * @return int
+     */
+    private function getPetLevel(int $userId, int $petTypeId): int
+    {
+        // 这里应该调用宠物服务获取宠物等级
+        // 由于没有实际的宠物服务,这里返回一个模拟值
+        return 1;
+    }
+}

+ 193 - 0
app/Module/Activity/Logics/ParticipationLogic.php

@@ -0,0 +1,193 @@
+<?php
+
+namespace App\Module\Activity\Logics;
+
+use App\Module\Activity\Dtos\ActivityParticipationDto;
+use App\Module\Activity\Dtos\UserActivityDataDto;
+use App\Module\Activity\Enums\PARTICIPATION_STATUS;
+use App\Module\Activity\Enums\REWARD_STATUS;
+use App\Module\Activity\Models\ActivityParticipation;
+use App\Module\Activity\Models\UserActivityData;
+use Carbon\Carbon;
+use Exception;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 参与逻辑类
+ */
+class ParticipationLogic
+{
+    /**
+     * 获取用户参与记录
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return ActivityParticipationDto|null
+     */
+    public function getUserParticipation(int $userId, int $activityId): ?ActivityParticipationDto
+    {
+        $participation = ActivityParticipation::where('user_id', $userId)
+            ->where('activity_id', $activityId)
+            ->first();
+        
+        if (!$participation) {
+            return null;
+        }
+        
+        return ActivityParticipationDto::fromModel($participation);
+    }
+
+    /**
+     * 获取用户活动数据
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return UserActivityDataDto|null
+     */
+    public function getUserActivityData(int $userId, int $activityId): ?UserActivityDataDto
+    {
+        $userData = UserActivityData::where('user_id', $userId)
+            ->where('activity_id', $activityId)
+            ->first();
+        
+        if (!$userData) {
+            return null;
+        }
+        
+        return UserActivityDataDto::fromModel($userData);
+    }
+
+    /**
+     * 创建参与记录
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return ActivityParticipationDto
+     * @throws Exception
+     */
+    public function createParticipation(int $userId, int $activityId): ActivityParticipationDto
+    {
+        // 检查是否已存在参与记录
+        $existingParticipation = ActivityParticipation::where('user_id', $userId)
+            ->where('activity_id', $activityId)
+            ->first();
+        
+        if ($existingParticipation) {
+            throw new Exception('用户已参与此活动');
+        }
+        
+        // 开始事务
+        DB::beginTransaction();
+        
+        try {
+            // 创建参与记录
+            $participation = new ActivityParticipation();
+            $participation->user_id = $userId;
+            $participation->activity_id = $activityId;
+            $participation->participate_time = Carbon::now();
+            $participation->reward_status = REWARD_STATUS::NOT_CLAIMED;
+            $participation->completion_status = PARTICIPATION_STATUS::IN_PROGRESS;
+            $participation->save();
+            
+            // 创建用户活动数据
+            $userData = new UserActivityData();
+            $userData->user_id = $userId;
+            $userData->activity_id = $activityId;
+            $userData->progress = 0;
+            $userData->progress_data = [];
+            $userData->last_update = Carbon::now();
+            $userData->save();
+            
+            // 提交事务
+            DB::commit();
+            
+            return ActivityParticipationDto::fromModel($participation);
+        } catch (Exception $e) {
+            // 回滚事务
+            DB::rollBack();
+            throw $e;
+        }
+    }
+
+    /**
+     * 更新参与记录状态
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @param int $completionStatus 完成状态
+     * @param int|null $rewardStatus 奖励状态
+     * @return bool
+     * @throws Exception
+     */
+    public function updateParticipationStatus(int $userId, int $activityId, int $completionStatus, ?int $rewardStatus = null): bool
+    {
+        // 获取参与记录
+        $participation = ActivityParticipation::where('user_id', $userId)
+            ->where('activity_id', $activityId)
+            ->first();
+        
+        if (!$participation) {
+            throw new Exception('用户未参与此活动');
+        }
+        
+        // 更新完成状态
+        $participation->completion_status = $completionStatus;
+        
+        // 如果完成状态为已完成,设置完成时间
+        if ($completionStatus === PARTICIPATION_STATUS::COMPLETED && !$participation->completion_time) {
+            $participation->completion_time = Carbon::now();
+        }
+        
+        // 更新奖励状态
+        if ($rewardStatus !== null) {
+            $participation->reward_status = $rewardStatus;
+        }
+        
+        return $participation->save();
+    }
+
+    /**
+     * 获取用户进行中的活动
+     *
+     * @param int $userId 用户ID
+     * @return array
+     */
+    public function getUserInProgressActivities(int $userId): array
+    {
+        $participations = ActivityParticipation::where('user_id', $userId)
+            ->where('completion_status', PARTICIPATION_STATUS::IN_PROGRESS)
+            ->with('activity')
+            ->get();
+        
+        $result = [];
+        
+        foreach ($participations as $participation) {
+            $result[] = ActivityParticipationDto::fromModel($participation, true);
+        }
+        
+        return $result;
+    }
+
+    /**
+     * 获取用户已完成但未领取奖励的活动
+     *
+     * @param int $userId 用户ID
+     * @return array
+     */
+    public function getUserCompletedUnclaimedActivities(int $userId): array
+    {
+        $participations = ActivityParticipation::where('user_id', $userId)
+            ->where('completion_status', PARTICIPATION_STATUS::COMPLETED)
+            ->where('reward_status', REWARD_STATUS::NOT_CLAIMED)
+            ->with('activity')
+            ->get();
+        
+        $result = [];
+        
+        foreach ($participations as $participation) {
+            $result[] = ActivityParticipationDto::fromModel($participation, true);
+        }
+        
+        return $result;
+    }
+}

+ 163 - 0
app/Module/Activity/Logics/ProgressLogic.php

@@ -0,0 +1,163 @@
+<?php
+
+namespace App\Module\Activity\Logics;
+
+use App\Module\Activity\Dtos\UserActivityDataDto;
+use App\Module\Activity\Models\UserActivityData;
+use Carbon\Carbon;
+use Exception;
+
+/**
+ * 进度逻辑类
+ */
+class ProgressLogic
+{
+    /**
+     * 获取用户活动进度
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return UserActivityDataDto|null
+     */
+    public function getUserActivityProgress(int $userId, int $activityId): ?UserActivityDataDto
+    {
+        $userData = UserActivityData::where('user_id', $userId)
+            ->where('activity_id', $activityId)
+            ->first();
+        
+        if (!$userData) {
+            return null;
+        }
+        
+        return UserActivityDataDto::fromModel($userData);
+    }
+
+    /**
+     * 更新用户活动进度
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @param int $progress 进度值
+     * @param array|null $progressData 进度数据
+     * @return UserActivityDataDto
+     * @throws Exception
+     */
+    public function updateUserActivityProgress(int $userId, int $activityId, int $progress, ?array $progressData = null): UserActivityDataDto
+    {
+        // 获取或创建用户活动数据
+        $userData = UserActivityData::firstOrNew([
+            'user_id' => $userId,
+            'activity_id' => $activityId,
+        ]);
+        
+        // 设置进度值
+        $userData->progress = $progress;
+        
+        // 设置进度数据
+        if ($progressData !== null) {
+            $userData->progress_data = $progressData;
+        }
+        
+        // 更新最后更新时间
+        $userData->last_update = Carbon::now();
+        
+        // 保存数据
+        $userData->save();
+        
+        return UserActivityDataDto::fromModel($userData);
+    }
+
+    /**
+     * 增加用户活动进度
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @param int $increment 增量值
+     * @param array|null $progressData 进度数据
+     * @return UserActivityDataDto
+     * @throws Exception
+     */
+    public function incrementUserActivityProgress(int $userId, int $activityId, int $increment, ?array $progressData = null): UserActivityDataDto
+    {
+        // 获取或创建用户活动数据
+        $userData = UserActivityData::firstOrNew([
+            'user_id' => $userId,
+            'activity_id' => $activityId,
+        ]);
+        
+        // 如果是新创建的记录,设置初始值
+        if (!$userData->exists) {
+            $userData->progress = 0;
+            $userData->progress_data = [];
+        }
+        
+        // 增加进度值
+        $userData->progress += $increment;
+        
+        // 设置进度数据
+        if ($progressData !== null) {
+            $userData->progress_data = $progressData;
+        }
+        
+        // 更新最后更新时间
+        $userData->last_update = Carbon::now();
+        
+        // 保存数据
+        $userData->save();
+        
+        return UserActivityDataDto::fromModel($userData);
+    }
+
+    /**
+     * 重置用户活动进度
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return bool
+     */
+    public function resetUserActivityProgress(int $userId, int $activityId): bool
+    {
+        // 获取用户活动数据
+        $userData = UserActivityData::where('user_id', $userId)
+            ->where('activity_id', $activityId)
+            ->first();
+        
+        if (!$userData) {
+            return false;
+        }
+        
+        // 重置进度值和进度数据
+        $userData->progress = 0;
+        $userData->progress_data = [];
+        $userData->last_update = Carbon::now();
+        
+        return $userData->save();
+    }
+
+    /**
+     * 获取活动的总体进度统计
+     *
+     * @param int $activityId 活动ID
+     * @return array
+     */
+    public function getActivityProgressStats(int $activityId): array
+    {
+        // 获取所有用户的活动数据
+        $userDataList = UserActivityData::where('activity_id', $activityId)->get();
+        
+        // 计算统计数据
+        $totalUsers = $userDataList->count();
+        $totalProgress = $userDataList->sum('progress');
+        $averageProgress = $totalUsers > 0 ? $totalProgress / $totalUsers : 0;
+        $maxProgress = $userDataList->max('progress');
+        $minProgress = $userDataList->min('progress');
+        
+        return [
+            'total_users' => $totalUsers,
+            'total_progress' => $totalProgress,
+            'average_progress' => $averageProgress,
+            'max_progress' => $maxProgress,
+            'min_progress' => $minProgress,
+        ];
+    }
+}

+ 219 - 0
app/Module/Activity/Logics/RewardLogic.php

@@ -0,0 +1,219 @@
+<?php
+
+namespace App\Module\Activity\Logics;
+
+use App\Module\Activity\Dtos\ActivityRewardDto;
+use App\Module\Activity\Enums\REWARD_STATUS;
+use App\Module\Activity\Models\ActivityConfig;
+use App\Module\Activity\Models\ActivityParticipation;
+use Exception;
+use Illuminate\Support\Facades\Log;
+
+/**
+ * 奖励逻辑类
+ */
+class RewardLogic
+{
+    /**
+     * 检查用户是否可以领取活动奖励
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return bool
+     */
+    public function canClaimReward(int $userId, int $activityId): bool
+    {
+        // 获取用户参与记录
+        $participation = ActivityParticipation::where('user_id', $userId)
+            ->where('activity_id', $activityId)
+            ->first();
+        
+        if (!$participation) {
+            return false;
+        }
+        
+        // 检查是否已完成且未领取奖励
+        return $participation->completion_status === 1 && $participation->reward_status === REWARD_STATUS::NOT_CLAIMED;
+    }
+
+    /**
+     * 标记奖励为已领取
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return bool
+     * @throws Exception
+     */
+    public function markRewardAsClaimed(int $userId, int $activityId): bool
+    {
+        // 获取用户参与记录
+        $participation = ActivityParticipation::where('user_id', $userId)
+            ->where('activity_id', $activityId)
+            ->first();
+        
+        if (!$participation) {
+            throw new Exception('用户未参与此活动');
+        }
+        
+        if ($participation->completion_status !== 1) {
+            throw new Exception('活动未完成,无法领取奖励');
+        }
+        
+        if ($participation->reward_status === REWARD_STATUS::CLAIMED) {
+            throw new Exception('奖励已领取');
+        }
+        
+        // 更新奖励状态为已领取
+        $participation->reward_status = REWARD_STATUS::CLAIMED;
+        
+        return $participation->save();
+    }
+
+    /**
+     * 标记奖励为已过期
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return bool
+     * @throws Exception
+     */
+    public function markRewardAsExpired(int $userId, int $activityId): bool
+    {
+        // 获取用户参与记录
+        $participation = ActivityParticipation::where('user_id', $userId)
+            ->where('activity_id', $activityId)
+            ->first();
+        
+        if (!$participation) {
+            throw new Exception('用户未参与此活动');
+        }
+        
+        if ($participation->reward_status !== REWARD_STATUS::NOT_CLAIMED) {
+            throw new Exception('奖励状态不是未领取,无法标记为已过期');
+        }
+        
+        // 更新奖励状态为已过期
+        $participation->reward_status = REWARD_STATUS::EXPIRED;
+        
+        return $participation->save();
+    }
+
+    /**
+     * 获取活动奖励信息
+     *
+     * @param int $activityId 活动ID
+     * @return ActivityRewardDto|null
+     */
+    public function getActivityReward(int $activityId): ?ActivityRewardDto
+    {
+        // 获取活动信息
+        $activity = ActivityConfig::find($activityId);
+        
+        if (!$activity) {
+            return null;
+        }
+        
+        // 如果活动没有配置奖励组,返回空
+        if (!$activity->reward_group_id && !$activity->reward_group_code) {
+            return null;
+        }
+        
+        // 创建奖励DTO
+        $rewardDto = ActivityRewardDto::create(
+            $activity->reward_group_id,
+            $activity->reward_group_code
+        );
+        
+        // 尝试获取奖励组信息
+        try {
+            // 这里应该调用奖励组服务获取奖励组信息
+            // 由于没有实际的奖励组服务,这里只返回基本信息
+            $rewardDto->rewardGroupName = '活动奖励';
+            $rewardDto->rewardGroupDescription = '完成活动获得的奖励';
+            
+            // 模拟奖励项
+            $rewardDto->rewardItems = [
+                [
+                    'type' => 'item',
+                    'id' => 1001,
+                    'name' => '金币',
+                    'quantity' => 100
+                ]
+            ];
+        } catch (Exception $e) {
+            Log::error('获取奖励组信息失败', [
+                'activity_id' => $activityId,
+                'reward_group_id' => $activity->reward_group_id,
+                'reward_group_code' => $activity->reward_group_code,
+                'error' => $e->getMessage()
+            ]);
+        }
+        
+        return $rewardDto;
+    }
+
+    /**
+     * 发放活动奖励
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return array 奖励结果
+     * @throws Exception
+     */
+    public function grantActivityReward(int $userId, int $activityId): array
+    {
+        // 获取活动信息
+        $activity = ActivityConfig::find($activityId);
+        
+        if (!$activity) {
+            throw new Exception('活动不存在');
+        }
+        
+        // 如果活动没有配置奖励组,返回空结果
+        if (!$activity->reward_group_id && !$activity->reward_group_code) {
+            return [
+                'success' => true,
+                'message' => '活动未配置奖励',
+                'rewards' => []
+            ];
+        }
+        
+        // 尝试发放奖励
+        try {
+            // 使用奖励组服务发放奖励
+            $rewardGroupId = $activity->reward_group_id;
+            $rewardGroupCode = $activity->reward_group_code;
+            
+            // 调用奖励组服务
+            $rewardService = new \App\Module\Game\Services\RewardService();
+            $rewardResult = $rewardService::grantReward(
+                $userId,
+                $rewardGroupId ?: $rewardGroupCode,
+                'activity',
+                $activity->id
+            );
+            
+            if ($rewardResult->success) {
+                return [
+                    'success' => true,
+                    'message' => '奖励发放成功',
+                    'rewards' => $rewardResult->items
+                ];
+            } else {
+                return [
+                    'success' => false,
+                    'message' => $rewardResult->errorMessage,
+                    'rewards' => []
+                ];
+            }
+        } catch (Exception $e) {
+            Log::error('发放活动奖励失败', [
+                'user_id' => $userId,
+                'activity_id' => $activityId,
+                'error' => $e->getMessage()
+            ]);
+            
+            throw new Exception('发放奖励失败: ' . $e->getMessage());
+        }
+    }
+}

+ 103 - 0
app/Module/Activity/Models/ActivityCondition.php

@@ -0,0 +1,103 @@
+<?php
+
+namespace App\Module\Activity\Models;
+
+use App\Module\Activity\Enums\CONDITION_TYPE;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use UCore\ModelCore;
+
+/**
+ * 活动条件
+ *
+ * field start 
+ * @property   int  $id  主键
+ * @property   int  $activity_id  关联活动ID
+ * @property   int  $condition_type  条件类型(1:等级要求, 2:道具要求, 3:时间要求等)
+ * @property   object|array  $condition_params  条件参数,JSON格式
+ * @property   int  $is_participation_condition  是否为参与条件(0:否, 1:是)
+ * @property   int  $is_completion_condition  是否为完成条件(0:否, 1:是)
+ * @property   int  $display_order  显示顺序
+ * @property   \Carbon\Carbon  $created_at  创建时间
+ * @property   \Carbon\Carbon  $updated_at  更新时间
+ * field end
+ */
+class ActivityCondition extends ModelCore
+{
+    /**
+     * 与模型关联的表名
+     *
+     * @var string
+     */
+    protected $table = 'activity_condition';
+
+    /**
+     * 可批量赋值的属性
+     *
+     * @var array
+     */
+    // attrlist start 
+    protected $fillable = [
+        'id',
+        'activity_id',
+        'condition_type',
+        'condition_params',
+        'is_participation_condition',
+        'is_completion_condition',
+        'display_order',
+    ];
+    // attrlist end
+
+    /**
+     * 应该被转换为原生类型的属性
+     *
+     * @var array
+     */
+    protected $casts = [
+        'activity_id' => 'integer',
+        'condition_type' => 'integer',
+        'condition_params' => 'json',
+        'is_participation_condition' => 'boolean',
+        'is_completion_condition' => 'boolean',
+        'display_order' => 'integer',
+    ];
+
+    /**
+     * 获取关联的活动
+     *
+     * @return BelongsTo
+     */
+    public function activity(): BelongsTo
+    {
+        return $this->belongsTo(ActivityConfig::class, 'activity_id', 'id');
+    }
+
+    /**
+     * 获取条件类型名称
+     *
+     * @return string
+     */
+    public function getConditionTypeName(): string
+    {
+        return CONDITION_TYPE::getName($this->condition_type);
+    }
+
+    /**
+     * 检查是否为参与条件
+     *
+     * @return bool
+     */
+    public function isParticipationCondition(): bool
+    {
+        return (bool)$this->is_participation_condition;
+    }
+
+    /**
+     * 检查是否为完成条件
+     *
+     * @return bool
+     */
+    public function isCompletionCondition(): bool
+    {
+        return (bool)$this->is_completion_condition;
+    }
+}

+ 157 - 0
app/Module/Activity/Models/ActivityConfig.php

@@ -0,0 +1,157 @@
+<?php
+
+namespace App\Module\Activity\Models;
+
+use App\Module\Activity\Enums\ACTIVITY_STATUS;
+use App\Module\Activity\Enums\ACTIVITY_TYPE;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+use UCore\ModelCore;
+
+/**
+ * 活动基础配置
+ *
+ * field start 
+ * @property   int  $id  主键
+ * @property   string  $name  活动名称
+ * @property   int  $type  活动类型(1:礼包活动, 2:限时活动, 3:任务活动, 4:签到活动, 5:节日活动)
+ * @property   string  $description  活动描述
+ * @property   \Carbon\Carbon  $start_time  开始时间
+ * @property   \Carbon\Carbon  $end_time  结束时间
+ * @property   int  $status  活动状态(0:未开始, 1:进行中, 2:已结束, 3:已关闭)
+ * @property   int  $display_order  显示顺序,数值越大越靠前
+ * @property   string  $icon  活动图标URL
+ * @property   string  $banner  活动横幅URL
+ * @property   int  $reward_group_id  奖励组ID(关联game_reward_groups表)
+ * @property   string  $reward_group_code  奖励组编码(关联game_reward_groups表的code字段)
+ * @property   object|array  $config_params  活动特定配置参数,JSON格式
+ * @property   \Carbon\Carbon  $created_at  创建时间
+ * @property   \Carbon\Carbon  $updated_at  更新时间
+ * field end
+ */
+class ActivityConfig extends ModelCore
+{
+    /**
+     * 与模型关联的表名
+     *
+     * @var string
+     */
+    protected $table = 'activity_config';
+
+    /**
+     * 可批量赋值的属性
+     *
+     * @var array
+     */
+    // attrlist start 
+    protected $fillable = [
+        'id',
+        'name',
+        'type',
+        'description',
+        'start_time',
+        'end_time',
+        'status',
+        'display_order',
+        'icon',
+        'banner',
+        'reward_group_id',
+        'reward_group_code',
+        'config_params',
+    ];
+    // attrlist end
+
+    /**
+     * 应该被转换为原生类型的属性
+     *
+     * @var array
+     */
+    protected $casts = [
+        'type' => 'integer',
+        'status' => 'integer',
+        'display_order' => 'integer',
+        'reward_group_id' => 'integer',
+        'config_params' => 'json',
+        'start_time' => 'datetime',
+        'end_time' => 'datetime',
+    ];
+
+    /**
+     * 获取活动类型名称
+     *
+     * @return string
+     */
+    public function getTypeName(): string
+    {
+        return ACTIVITY_TYPE::getName($this->type);
+    }
+
+    /**
+     * 获取活动状态名称
+     *
+     * @return string
+     */
+    public function getStatusName(): string
+    {
+        return ACTIVITY_STATUS::getName($this->status);
+    }
+
+    /**
+     * 获取活动的参与记录
+     *
+     * @return HasMany
+     */
+    public function participations(): HasMany
+    {
+        return $this->hasMany(ActivityParticipation::class, 'activity_id', 'id');
+    }
+
+    /**
+     * 获取活动的用户数据
+     *
+     * @return HasMany
+     */
+    public function userData(): HasMany
+    {
+        return $this->hasMany(UserActivityData::class, 'activity_id', 'id');
+    }
+
+    /**
+     * 获取活动的条件
+     *
+     * @return HasMany
+     */
+    public function conditions(): HasMany
+    {
+        return $this->hasMany(ActivityCondition::class, 'activity_id', 'id');
+    }
+
+    /**
+     * 检查活动是否进行中
+     *
+     * @return bool
+     */
+    public function isInProgress(): bool
+    {
+        return $this->status === ACTIVITY_STATUS::IN_PROGRESS;
+    }
+
+    /**
+     * 检查活动是否已结束
+     *
+     * @return bool
+     */
+    public function isEnded(): bool
+    {
+        return $this->status === ACTIVITY_STATUS::ENDED || $this->status === ACTIVITY_STATUS::CLOSED;
+    }
+
+    /**
+     * 检查活动是否未开始
+     *
+     * @return bool
+     */
+    public function isNotStarted(): bool
+    {
+        return $this->status === ACTIVITY_STATUS::NOT_STARTED;
+    }
+}

+ 154 - 0
app/Module/Activity/Models/ActivityParticipation.php

@@ -0,0 +1,154 @@
+<?php
+
+namespace App\Module\Activity\Models;
+
+use App\Module\Activity\Enums\PARTICIPATION_STATUS;
+use App\Module\Activity\Enums\REWARD_STATUS;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use UCore\ModelCore;
+
+/**
+ * 活动参与记录
+ *
+ * field start 
+ * @property   int  $id  主键
+ * @property   int  $user_id  用户ID
+ * @property   int  $activity_id  活动ID
+ * @property   \Carbon\Carbon  $participate_time  参与时间
+ * @property   int  $reward_status  奖励状态(0:未领取, 1:已领取, 2:已过期)
+ * @property   int  $completion_status  完成状态(0:进行中, 1:已完成, 2:已失败)
+ * @property   \Carbon\Carbon  $completion_time  完成时间
+ * @property   \Carbon\Carbon  $created_at  创建时间
+ * @property   \Carbon\Carbon  $updated_at  更新时间
+ * field end
+ */
+class ActivityParticipation extends ModelCore
+{
+    /**
+     * 与模型关联的表名
+     *
+     * @var string
+     */
+    protected $table = 'activity_participation';
+
+    /**
+     * 可批量赋值的属性
+     *
+     * @var array
+     */
+    // attrlist start 
+    protected $fillable = [
+        'id',
+        'user_id',
+        'activity_id',
+        'participate_time',
+        'reward_status',
+        'completion_status',
+        'completion_time',
+    ];
+    // attrlist end
+
+    /**
+     * 应该被转换为原生类型的属性
+     *
+     * @var array
+     */
+    protected $casts = [
+        'user_id' => 'integer',
+        'activity_id' => 'integer',
+        'reward_status' => 'integer',
+        'completion_status' => 'integer',
+        'participate_time' => 'datetime',
+        'completion_time' => 'datetime',
+    ];
+
+    /**
+     * 获取关联的活动
+     *
+     * @return BelongsTo
+     */
+    public function activity(): BelongsTo
+    {
+        return $this->belongsTo(ActivityConfig::class, 'activity_id', 'id');
+    }
+
+    /**
+     * 获取奖励状态名称
+     *
+     * @return string
+     */
+    public function getRewardStatusName(): string
+    {
+        return REWARD_STATUS::getName($this->reward_status);
+    }
+
+    /**
+     * 获取完成状态名称
+     *
+     * @return string
+     */
+    public function getCompletionStatusName(): string
+    {
+        return PARTICIPATION_STATUS::getName($this->completion_status);
+    }
+
+    /**
+     * 检查是否已完成
+     *
+     * @return bool
+     */
+    public function isCompleted(): bool
+    {
+        return $this->completion_status === PARTICIPATION_STATUS::COMPLETED;
+    }
+
+    /**
+     * 检查是否进行中
+     *
+     * @return bool
+     */
+    public function isInProgress(): bool
+    {
+        return $this->completion_status === PARTICIPATION_STATUS::IN_PROGRESS;
+    }
+
+    /**
+     * 检查是否已失败
+     *
+     * @return bool
+     */
+    public function isFailed(): bool
+    {
+        return $this->completion_status === PARTICIPATION_STATUS::FAILED;
+    }
+
+    /**
+     * 检查奖励是否已领取
+     *
+     * @return bool
+     */
+    public function isRewardClaimed(): bool
+    {
+        return $this->reward_status === REWARD_STATUS::CLAIMED;
+    }
+
+    /**
+     * 检查奖励是否未领取
+     *
+     * @return bool
+     */
+    public function isRewardNotClaimed(): bool
+    {
+        return $this->reward_status === REWARD_STATUS::NOT_CLAIMED;
+    }
+
+    /**
+     * 检查奖励是否已过期
+     *
+     * @return bool
+     */
+    public function isRewardExpired(): bool
+    {
+        return $this->reward_status === REWARD_STATUS::EXPIRED;
+    }
+}

+ 111 - 0
app/Module/Activity/Models/UserActivityData.php

@@ -0,0 +1,111 @@
+<?php
+
+namespace App\Module\Activity\Models;
+
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use UCore\ModelCore;
+
+/**
+ * 用户活动数据
+ *
+ * field start 
+ * @property   int  $id  主键
+ * @property   int  $user_id  用户ID
+ * @property   int  $activity_id  活动ID
+ * @property   int  $progress  活动进度(如任务完成数等)
+ * @property   object|array  $progress_data  详细进度数据,JSON格式
+ * @property   \Carbon\Carbon  $last_update  最后更新时间
+ * @property   \Carbon\Carbon  $created_at  创建时间
+ * @property   \Carbon\Carbon  $updated_at  更新时间
+ * field end
+ */
+class UserActivityData extends ModelCore
+{
+    /**
+     * 与模型关联的表名
+     *
+     * @var string
+     */
+    protected $table = 'user_activity_data';
+
+    /**
+     * 可批量赋值的属性
+     *
+     * @var array
+     */
+    // attrlist start 
+    protected $fillable = [
+        'id',
+        'user_id',
+        'activity_id',
+        'progress',
+        'progress_data',
+        'last_update',
+    ];
+    // attrlist end
+
+    /**
+     * 应该被转换为原生类型的属性
+     *
+     * @var array
+     */
+    protected $casts = [
+        'user_id' => 'integer',
+        'activity_id' => 'integer',
+        'progress' => 'integer',
+        'progress_data' => 'json',
+        'last_update' => 'datetime',
+    ];
+
+    /**
+     * 获取关联的活动
+     *
+     * @return BelongsTo
+     */
+    public function activity(): BelongsTo
+    {
+        return $this->belongsTo(ActivityConfig::class, 'activity_id', 'id');
+    }
+
+    /**
+     * 获取关联的参与记录
+     *
+     * @return BelongsTo
+     */
+    public function participation(): BelongsTo
+    {
+        return $this->belongsTo(ActivityParticipation::class, ['user_id', 'activity_id'], ['user_id', 'activity_id']);
+    }
+
+    /**
+     * 更新进度
+     *
+     * @param int $progress 新的进度值
+     * @param array|null $progressData 详细进度数据
+     * @return bool
+     */
+    public function updateProgress(int $progress, ?array $progressData = null): bool
+    {
+        $this->progress = $progress;
+        
+        if ($progressData !== null) {
+            $this->progress_data = $progressData;
+        }
+        
+        $this->last_update = now();
+        
+        return $this->save();
+    }
+
+    /**
+     * 增加进度
+     *
+     * @param int $increment 增加的进度值
+     * @param array|null $progressData 详细进度数据
+     * @return bool
+     */
+    public function incrementProgress(int $increment, ?array $progressData = null): bool
+    {
+        return $this->updateProgress($this->progress + $increment, $progressData);
+    }
+}

+ 95 - 0
app/Module/Activity/Providers/ActivityServiceProvider.php

@@ -0,0 +1,95 @@
+<?php
+
+namespace App\Module\Activity\Providers;
+
+use App\Module\Activity\Commands\CleanExpiredActivitiesCommand;
+use App\Module\Activity\Commands\UpdateActivityStatusCommand;
+use App\Module\Activity\Events\ActivityCompletedEvent;
+use App\Module\Activity\Events\ActivityCreatedEvent;
+use App\Module\Activity\Events\ActivityProgressUpdatedEvent;
+use App\Module\Activity\Events\ActivityRewardClaimedEvent;
+use App\Module\Activity\Events\ActivityStatusChangedEvent;
+use App\Module\Activity\Events\UserParticipatedEvent;
+use App\Module\Activity\Listeners\ActivityCompletedListener;
+use App\Module\Activity\Listeners\ActivityProgressListener;
+use App\Module\Activity\Listeners\ActivityStatusChangeListener;
+use App\Module\Activity\Listeners\RewardDistributionListener;
+use App\Module\Activity\Listeners\UserParticipationListener;
+use Illuminate\Support\Facades\Event;
+use Illuminate\Support\ServiceProvider;
+
+/**
+ * 活动模块服务提供者
+ */
+class ActivityServiceProvider extends ServiceProvider
+{
+    /**
+     * 要注册的命令
+     *
+     * @var array
+     */
+    protected $commands = [
+        UpdateActivityStatusCommand::class,
+        CleanExpiredActivitiesCommand::class,
+    ];
+
+    /**
+     * 注册服务
+     *
+     * @return void
+     */
+    public function register()
+    {
+        // 注册命令
+        $this->commands($this->commands);
+    }
+
+    /**
+     * 启动服务
+     *
+     * @return void
+     */
+    public function boot()
+    {
+        // 注册事件监听器
+        $this->registerEventListeners();
+    }
+
+    /**
+     * 注册事件监听器
+     *
+     * @return void
+     */
+    protected function registerEventListeners()
+    {
+        // 活动状态变更事件
+        Event::listen(
+            ActivityStatusChangedEvent::class,
+            ActivityStatusChangeListener::class
+        );
+
+        // 用户参与活动事件
+        Event::listen(
+            UserParticipatedEvent::class,
+            UserParticipationListener::class
+        );
+
+        // 活动进度更新事件
+        Event::listen(
+            ActivityProgressUpdatedEvent::class,
+            ActivityProgressListener::class
+        );
+
+        // 活动完成事件
+        Event::listen(
+            ActivityCompletedEvent::class,
+            ActivityCompletedListener::class
+        );
+
+        // 活动奖励领取事件
+        Event::listen(
+            ActivityRewardClaimedEvent::class,
+            RewardDistributionListener::class
+        );
+    }
+}

+ 22 - 0
app/Module/Activity/Repositorys/ActivityConditionRepository.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace App\Module\Activity\Repositorys;
+
+use App\Module\Activity\Models\ActivityCondition;
+use Dcat\Admin\Repositories\EloquentRepository;
+
+/**
+ * 活动条件数据仓库类
+ *
+ * 提供活动条件数据的访问和操作功能。
+ * 该类是活动条件模块与后台管理系统的桥梁,用于处理活动条件数据的CRUD操作。
+ */
+class ActivityConditionRepository extends EloquentRepository
+{
+    /**
+     * 关联的Eloquent模型类
+     *
+     * @var string
+     */
+    protected $eloquentClass = ActivityCondition::class;
+}

+ 22 - 0
app/Module/Activity/Repositorys/ActivityConfigRepository.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace App\Module\Activity\Repositorys;
+
+use App\Module\Activity\Models\ActivityConfig;
+use Dcat\Admin\Repositories\EloquentRepository;
+
+/**
+ * 活动配置数据仓库类
+ *
+ * 提供活动配置数据的访问和操作功能。
+ * 该类是活动配置模块与后台管理系统的桥梁,用于处理活动配置数据的CRUD操作。
+ */
+class ActivityConfigRepository extends EloquentRepository
+{
+    /**
+     * 关联的Eloquent模型类
+     *
+     * @var string
+     */
+    protected $eloquentClass = ActivityConfig::class;
+}

+ 22 - 0
app/Module/Activity/Repositorys/ActivityParticipationRepository.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace App\Module\Activity\Repositorys;
+
+use App\Module\Activity\Models\ActivityParticipation;
+use Dcat\Admin\Repositories\EloquentRepository;
+
+/**
+ * 活动参与记录数据仓库类
+ *
+ * 提供活动参与记录数据的访问和操作功能。
+ * 该类是活动参与记录模块与后台管理系统的桥梁,用于处理活动参与记录数据的CRUD操作。
+ */
+class ActivityParticipationRepository extends EloquentRepository
+{
+    /**
+     * 关联的Eloquent模型类
+     *
+     * @var string
+     */
+    protected $eloquentClass = ActivityParticipation::class;
+}

+ 22 - 0
app/Module/Activity/Repositorys/UserActivityDataRepository.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace App\Module\Activity\Repositorys;
+
+use App\Module\Activity\Models\UserActivityData;
+use Dcat\Admin\Repositories\EloquentRepository;
+
+/**
+ * 用户活动数据仓库类
+ *
+ * 提供用户活动数据的访问和操作功能。
+ * 该类是用户活动数据模块与后台管理系统的桥梁,用于处理用户活动数据的CRUD操作。
+ */
+class UserActivityDataRepository extends EloquentRepository
+{
+    /**
+     * 关联的Eloquent模型类
+     *
+     * @var string
+     */
+    protected $eloquentClass = UserActivityData::class;
+}

+ 373 - 0
app/Module/Activity/Services/ActivityManagementService.php

@@ -0,0 +1,373 @@
+<?php
+
+namespace App\Module\Activity\Services;
+
+use App\Module\Activity\Dtos\ActivityConfigDto;
+use App\Module\Activity\Enums\ACTIVITY_STATUS;
+use App\Module\Activity\Models\ActivityConfig;
+use App\Module\Activity\Models\ActivityCondition;
+use Carbon\Carbon;
+use Exception;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+
+/**
+ * 活动管理服务类
+ */
+class ActivityManagementService
+{
+    /**
+     * 创建活动
+     *
+     * @param array $data 活动数据
+     * @return array
+     */
+    public static function createActivity(array $data): array
+    {
+        try {
+            // 开始事务
+            DB::beginTransaction();
+            
+            // 创建活动
+            $activity = new ActivityConfig();
+            $activity->name = $data['name'];
+            $activity->type = $data['type'];
+            $activity->description = $data['description'] ?? '';
+            $activity->start_time = Carbon::parse($data['start_time']);
+            $activity->end_time = Carbon::parse($data['end_time']);
+            $activity->status = $data['status'] ?? ACTIVITY_STATUS::NOT_STARTED;
+            $activity->display_order = $data['display_order'] ?? 0;
+            $activity->icon = $data['icon'] ?? '';
+            $activity->banner = $data['banner'] ?? '';
+            $activity->reward_group_id = $data['reward_group_id'] ?? null;
+            $activity->reward_group_code = $data['reward_group_code'] ?? null;
+            $activity->config_params = $data['config_params'] ?? [];
+            $activity->save();
+            
+            // 创建活动条件
+            if (!empty($data['conditions']) && is_array($data['conditions'])) {
+                foreach ($data['conditions'] as $conditionData) {
+                    $condition = new ActivityCondition();
+                    $condition->activity_id = $activity->id;
+                    $condition->condition_type = $conditionData['condition_type'];
+                    $condition->condition_params = $conditionData['condition_params'] ?? [];
+                    $condition->is_participation_condition = $conditionData['is_participation_condition'] ?? false;
+                    $condition->is_completion_condition = $conditionData['is_completion_condition'] ?? false;
+                    $condition->display_order = $conditionData['display_order'] ?? 0;
+                    $condition->save();
+                }
+            }
+            
+            // 提交事务
+            DB::commit();
+            
+            return [
+                'success' => true,
+                'message' => '创建活动成功',
+                'activity_id' => $activity->id
+            ];
+        } catch (Exception $e) {
+            // 回滚事务
+            DB::rollBack();
+            
+            Log::error('创建活动失败', [
+                'data' => $data,
+                'error' => $e->getMessage()
+            ]);
+            
+            return [
+                'success' => false,
+                'message' => $e->getMessage()
+            ];
+        }
+    }
+
+    /**
+     * 更新活动
+     *
+     * @param int $activityId 活动ID
+     * @param array $data 活动数据
+     * @return array
+     */
+    public static function updateActivity(int $activityId, array $data): array
+    {
+        try {
+            // 获取活动
+            $activity = ActivityConfig::findOrFail($activityId);
+            
+            // 开始事务
+            DB::beginTransaction();
+            
+            // 更新活动
+            if (isset($data['name'])) {
+                $activity->name = $data['name'];
+            }
+            
+            if (isset($data['type'])) {
+                $activity->type = $data['type'];
+            }
+            
+            if (isset($data['description'])) {
+                $activity->description = $data['description'];
+            }
+            
+            if (isset($data['start_time'])) {
+                $activity->start_time = Carbon::parse($data['start_time']);
+            }
+            
+            if (isset($data['end_time'])) {
+                $activity->end_time = Carbon::parse($data['end_time']);
+            }
+            
+            if (isset($data['status'])) {
+                $activity->status = $data['status'];
+            }
+            
+            if (isset($data['display_order'])) {
+                $activity->display_order = $data['display_order'];
+            }
+            
+            if (isset($data['icon'])) {
+                $activity->icon = $data['icon'];
+            }
+            
+            if (isset($data['banner'])) {
+                $activity->banner = $data['banner'];
+            }
+            
+            if (isset($data['reward_group_id'])) {
+                $activity->reward_group_id = $data['reward_group_id'];
+            }
+            
+            if (isset($data['reward_group_code'])) {
+                $activity->reward_group_code = $data['reward_group_code'];
+            }
+            
+            if (isset($data['config_params'])) {
+                $activity->config_params = $data['config_params'];
+            }
+            
+            $activity->save();
+            
+            // 更新活动条件
+            if (!empty($data['conditions']) && is_array($data['conditions'])) {
+                // 删除旧条件
+                ActivityCondition::where('activity_id', $activityId)->delete();
+                
+                // 创建新条件
+                foreach ($data['conditions'] as $conditionData) {
+                    $condition = new ActivityCondition();
+                    $condition->activity_id = $activity->id;
+                    $condition->condition_type = $conditionData['condition_type'];
+                    $condition->condition_params = $conditionData['condition_params'] ?? [];
+                    $condition->is_participation_condition = $conditionData['is_participation_condition'] ?? false;
+                    $condition->is_completion_condition = $conditionData['is_completion_condition'] ?? false;
+                    $condition->display_order = $conditionData['display_order'] ?? 0;
+                    $condition->save();
+                }
+            }
+            
+            // 提交事务
+            DB::commit();
+            
+            return [
+                'success' => true,
+                'message' => '更新活动成功'
+            ];
+        } catch (Exception $e) {
+            // 回滚事务
+            DB::rollBack();
+            
+            Log::error('更新活动失败', [
+                'activity_id' => $activityId,
+                'data' => $data,
+                'error' => $e->getMessage()
+            ]);
+            
+            return [
+                'success' => false,
+                'message' => $e->getMessage()
+            ];
+        }
+    }
+
+    /**
+     * 删除活动
+     *
+     * @param int $activityId 活动ID
+     * @return array
+     */
+    public static function deleteActivity(int $activityId): array
+    {
+        try {
+            // 开始事务
+            DB::beginTransaction();
+            
+            // 删除活动条件
+            ActivityCondition::where('activity_id', $activityId)->delete();
+            
+            // 删除活动
+            ActivityConfig::where('id', $activityId)->delete();
+            
+            // 提交事务
+            DB::commit();
+            
+            return [
+                'success' => true,
+                'message' => '删除活动成功'
+            ];
+        } catch (Exception $e) {
+            // 回滚事务
+            DB::rollBack();
+            
+            Log::error('删除活动失败', [
+                'activity_id' => $activityId,
+                'error' => $e->getMessage()
+            ]);
+            
+            return [
+                'success' => false,
+                'message' => $e->getMessage()
+            ];
+        }
+    }
+
+    /**
+     * 更新活动状态
+     *
+     * @param int $activityId 活动ID
+     * @param int $status 状态
+     * @return array
+     */
+    public static function updateActivityStatus(int $activityId, int $status): array
+    {
+        try {
+            // 获取活动
+            $activity = ActivityConfig::findOrFail($activityId);
+            
+            // 更新状态
+            $activity->status = $status;
+            $activity->save();
+            
+            return [
+                'success' => true,
+                'message' => '更新活动状态成功'
+            ];
+        } catch (Exception $e) {
+            Log::error('更新活动状态失败', [
+                'activity_id' => $activityId,
+                'status' => $status,
+                'error' => $e->getMessage()
+            ]);
+            
+            return [
+                'success' => false,
+                'message' => $e->getMessage()
+            ];
+        }
+    }
+
+    /**
+     * 获取所有活动
+     *
+     * @param array $filters 过滤条件
+     * @return array
+     */
+    public static function getAllActivities(array $filters = []): array
+    {
+        try {
+            $query = ActivityConfig::query();
+            
+            // 应用过滤条件
+            if (!empty($filters['status'])) {
+                $query->where('status', $filters['status']);
+            }
+            
+            if (!empty($filters['type'])) {
+                $query->where('type', $filters['type']);
+            }
+            
+            if (!empty($filters['name'])) {
+                $query->where('name', 'like', "%{$filters['name']}%");
+            }
+            
+            if (!empty($filters['start_time'])) {
+                $query->where('start_time', '>=', Carbon::parse($filters['start_time']));
+            }
+            
+            if (!empty($filters['end_time'])) {
+                $query->where('end_time', '<=', Carbon::parse($filters['end_time']));
+            }
+            
+            // 排序
+            $query->orderBy('display_order', 'desc')
+                ->orderBy('id', 'desc');
+            
+            // 获取活动列表
+            $activities = $query->get();
+            
+            $result = [];
+            foreach ($activities as $activity) {
+                $result[] = ActivityConfigDto::fromModel($activity);
+            }
+            
+            return $result;
+        } catch (Exception $e) {
+            Log::error('获取所有活动失败', [
+                'filters' => $filters,
+                'error' => $e->getMessage()
+            ]);
+            
+            return [];
+        }
+    }
+
+    /**
+     * 自动更新活动状态
+     *
+     * @return array
+     */
+    public static function autoUpdateActivityStatus(): array
+    {
+        try {
+            $now = Carbon::now();
+            $updated = 0;
+            
+            // 更新未开始的活动
+            $notStartedActivities = ActivityConfig::where('status', ACTIVITY_STATUS::NOT_STARTED)
+                ->where('start_time', '<=', $now)
+                ->get();
+            
+            foreach ($notStartedActivities as $activity) {
+                $activity->status = ACTIVITY_STATUS::IN_PROGRESS;
+                $activity->save();
+                $updated++;
+            }
+            
+            // 更新进行中的活动
+            $inProgressActivities = ActivityConfig::where('status', ACTIVITY_STATUS::IN_PROGRESS)
+                ->where('end_time', '<', $now)
+                ->get();
+            
+            foreach ($inProgressActivities as $activity) {
+                $activity->status = ACTIVITY_STATUS::ENDED;
+                $activity->save();
+                $updated++;
+            }
+            
+            return [
+                'success' => true,
+                'message' => "自动更新活动状态成功,共更新 {$updated} 个活动"
+            ];
+        } catch (Exception $e) {
+            Log::error('自动更新活动状态失败', [
+                'error' => $e->getMessage()
+            ]);
+            
+            return [
+                'success' => false,
+                'message' => $e->getMessage()
+            ];
+        }
+    }
+}

+ 320 - 0
app/Module/Activity/Services/ActivityService.php

@@ -0,0 +1,320 @@
+<?php
+
+namespace App\Module\Activity\Services;
+
+use App\Module\Activity\Dtos\ActivityConfigDto;
+use App\Module\Activity\Dtos\ActivityParticipationDto;
+use App\Module\Activity\Dtos\UserActivityDataDto;
+use App\Module\Activity\Logics\ActivityLogic;
+use App\Module\Activity\Logics\ParticipationLogic;
+use App\Module\Activity\Logics\ProgressLogic;
+use App\Module\Activity\Logics\RewardLogic;
+use Exception;
+use Illuminate\Support\Facades\Log;
+
+/**
+ * 活动服务类
+ */
+class ActivityService
+{
+    /**
+     * 获取活动详情
+     *
+     * @param int $activityId 活动ID
+     * @param bool $withConditions 是否包含条件
+     * @return ActivityConfigDto|null
+     */
+    public static function getActivityDetail(int $activityId, bool $withConditions = false): ?ActivityConfigDto
+    {
+        try {
+            $activityLogic = new ActivityLogic();
+            return $activityLogic->getActivityDetail($activityId, $withConditions);
+        } catch (Exception $e) {
+            Log::error('获取活动详情失败', [
+                'activity_id' => $activityId,
+                'error' => $e->getMessage()
+            ]);
+            return null;
+        }
+    }
+
+    /**
+     * 获取用户可参与的活动列表
+     *
+     * @param int $userId 用户ID
+     * @return array
+     */
+    public static function getUserAvailableActivities(int $userId): array
+    {
+        try {
+            $activityLogic = new ActivityLogic();
+            return $activityLogic->getUserAvailableActivities($userId);
+        } catch (Exception $e) {
+            Log::error('获取用户可参与活动列表失败', [
+                'user_id' => $userId,
+                'error' => $e->getMessage()
+            ]);
+            return [];
+        }
+    }
+
+    /**
+     * 参与活动
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return array
+     */
+    public static function participateActivity(int $userId, int $activityId): array
+    {
+        try {
+            $activityLogic = new ActivityLogic();
+            $participation = $activityLogic->participateActivity($userId, $activityId);
+            
+            return [
+                'success' => true,
+                'message' => '参与活动成功',
+                'participation' => $participation
+            ];
+        } catch (Exception $e) {
+            Log::error('参与活动失败', [
+                'user_id' => $userId,
+                'activity_id' => $activityId,
+                'error' => $e->getMessage()
+            ]);
+            
+            return [
+                'success' => false,
+                'message' => $e->getMessage()
+            ];
+        }
+    }
+
+    /**
+     * 更新活动进度
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @param int $progress 进度值
+     * @param array|null $progressData 进度数据
+     * @return array
+     */
+    public static function updateActivityProgress(int $userId, int $activityId, int $progress, ?array $progressData = null): array
+    {
+        try {
+            $activityLogic = new ActivityLogic();
+            $result = $activityLogic->updateActivityProgress($userId, $activityId, $progress, $progressData);
+            
+            return [
+                'success' => $result,
+                'message' => $result ? '更新进度成功' : '更新进度失败'
+            ];
+        } catch (Exception $e) {
+            Log::error('更新活动进度失败', [
+                'user_id' => $userId,
+                'activity_id' => $activityId,
+                'progress' => $progress,
+                'error' => $e->getMessage()
+            ]);
+            
+            return [
+                'success' => false,
+                'message' => $e->getMessage()
+            ];
+        }
+    }
+
+    /**
+     * 增加活动进度
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @param int $increment 增量值
+     * @param array|null $progressData 进度数据
+     * @return array
+     */
+    public static function incrementActivityProgress(int $userId, int $activityId, int $increment, ?array $progressData = null): array
+    {
+        try {
+            $progressLogic = new ProgressLogic();
+            $participationLogic = new ParticipationLogic();
+            
+            // 获取用户参与记录
+            $participation = $participationLogic->getUserParticipation($userId, $activityId);
+            
+            if (!$participation) {
+                return [
+                    'success' => false,
+                    'message' => '用户未参与此活动'
+                ];
+            }
+            
+            // 获取当前进度
+            $userData = $progressLogic->getUserActivityProgress($userId, $activityId);
+            $currentProgress = $userData ? $userData->progress : 0;
+            
+            // 增加进度
+            $newUserData = $progressLogic->incrementUserActivityProgress($userId, $activityId, $increment, $progressData);
+            
+            // 更新活动进度
+            $activityLogic = new ActivityLogic();
+            $activityLogic->updateActivityProgress($userId, $activityId, $newUserData->progress, $newUserData->progressData);
+            
+            return [
+                'success' => true,
+                'message' => '增加进度成功',
+                'old_progress' => $currentProgress,
+                'new_progress' => $newUserData->progress
+            ];
+        } catch (Exception $e) {
+            Log::error('增加活动进度失败', [
+                'user_id' => $userId,
+                'activity_id' => $activityId,
+                'increment' => $increment,
+                'error' => $e->getMessage()
+            ]);
+            
+            return [
+                'success' => false,
+                'message' => $e->getMessage()
+            ];
+        }
+    }
+
+    /**
+     * 领取活动奖励
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return array
+     */
+    public static function claimActivityReward(int $userId, int $activityId): array
+    {
+        try {
+            $activityLogic = new ActivityLogic();
+            $result = $activityLogic->claimActivityReward($userId, $activityId);
+            
+            return [
+                'success' => $result,
+                'message' => $result ? '领取奖励成功' : '领取奖励失败'
+            ];
+        } catch (Exception $e) {
+            Log::error('领取活动奖励失败', [
+                'user_id' => $userId,
+                'activity_id' => $activityId,
+                'error' => $e->getMessage()
+            ]);
+            
+            return [
+                'success' => false,
+                'message' => $e->getMessage()
+            ];
+        }
+    }
+
+    /**
+     * 获取用户参与记录
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return ActivityParticipationDto|null
+     */
+    public static function getUserParticipation(int $userId, int $activityId): ?ActivityParticipationDto
+    {
+        try {
+            $participationLogic = new ParticipationLogic();
+            return $participationLogic->getUserParticipation($userId, $activityId);
+        } catch (Exception $e) {
+            Log::error('获取用户参与记录失败', [
+                'user_id' => $userId,
+                'activity_id' => $activityId,
+                'error' => $e->getMessage()
+            ]);
+            return null;
+        }
+    }
+
+    /**
+     * 获取用户活动进度
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return UserActivityDataDto|null
+     */
+    public static function getUserActivityProgress(int $userId, int $activityId): ?UserActivityDataDto
+    {
+        try {
+            $progressLogic = new ProgressLogic();
+            return $progressLogic->getUserActivityProgress($userId, $activityId);
+        } catch (Exception $e) {
+            Log::error('获取用户活动进度失败', [
+                'user_id' => $userId,
+                'activity_id' => $activityId,
+                'error' => $e->getMessage()
+            ]);
+            return null;
+        }
+    }
+
+    /**
+     * 检查用户是否可以领取活动奖励
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return bool
+     */
+    public static function canClaimReward(int $userId, int $activityId): bool
+    {
+        try {
+            $rewardLogic = new RewardLogic();
+            return $rewardLogic->canClaimReward($userId, $activityId);
+        } catch (Exception $e) {
+            Log::error('检查用户是否可以领取活动奖励失败', [
+                'user_id' => $userId,
+                'activity_id' => $activityId,
+                'error' => $e->getMessage()
+            ]);
+            return false;
+        }
+    }
+
+    /**
+     * 获取用户进行中的活动
+     *
+     * @param int $userId 用户ID
+     * @return array
+     */
+    public static function getUserInProgressActivities(int $userId): array
+    {
+        try {
+            $participationLogic = new ParticipationLogic();
+            return $participationLogic->getUserInProgressActivities($userId);
+        } catch (Exception $e) {
+            Log::error('获取用户进行中的活动失败', [
+                'user_id' => $userId,
+                'error' => $e->getMessage()
+            ]);
+            return [];
+        }
+    }
+
+    /**
+     * 获取用户已完成但未领取奖励的活动
+     *
+     * @param int $userId 用户ID
+     * @return array
+     */
+    public static function getUserCompletedUnclaimedActivities(int $userId): array
+    {
+        try {
+            $participationLogic = new ParticipationLogic();
+            return $participationLogic->getUserCompletedUnclaimedActivities($userId);
+        } catch (Exception $e) {
+            Log::error('获取用户已完成但未领取奖励的活动失败', [
+                'user_id' => $userId,
+                'error' => $e->getMessage()
+            ]);
+            return [];
+        }
+    }
+}

+ 131 - 0
app/Module/Activity/Services/RewardService.php

@@ -0,0 +1,131 @@
+<?php
+
+namespace App\Module\Activity\Services;
+
+use App\Module\Activity\Dtos\ActivityRewardDto;
+use App\Module\Activity\Logics\RewardLogic;
+use Exception;
+use Illuminate\Support\Facades\Log;
+
+/**
+ * 奖励服务类
+ */
+class RewardService
+{
+    /**
+     * 获取活动奖励信息
+     *
+     * @param int $activityId 活动ID
+     * @return ActivityRewardDto|null
+     */
+    public static function getActivityReward(int $activityId): ?ActivityRewardDto
+    {
+        try {
+            $rewardLogic = new RewardLogic();
+            return $rewardLogic->getActivityReward($activityId);
+        } catch (Exception $e) {
+            Log::error('获取活动奖励信息失败', [
+                'activity_id' => $activityId,
+                'error' => $e->getMessage()
+            ]);
+            return null;
+        }
+    }
+
+    /**
+     * 发放活动奖励
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return array
+     */
+    public static function grantActivityReward(int $userId, int $activityId): array
+    {
+        try {
+            $rewardLogic = new RewardLogic();
+            
+            // 检查是否可以领取奖励
+            if (!$rewardLogic->canClaimReward($userId, $activityId)) {
+                return [
+                    'success' => false,
+                    'message' => '不满足领取奖励条件',
+                    'rewards' => []
+                ];
+            }
+            
+            // 发放奖励
+            $result = $rewardLogic->grantActivityReward($userId, $activityId);
+            
+            // 如果发放成功,标记奖励为已领取
+            if ($result['success']) {
+                $rewardLogic->markRewardAsClaimed($userId, $activityId);
+            }
+            
+            return $result;
+        } catch (Exception $e) {
+            Log::error('发放活动奖励失败', [
+                'user_id' => $userId,
+                'activity_id' => $activityId,
+                'error' => $e->getMessage()
+            ]);
+            
+            return [
+                'success' => false,
+                'message' => $e->getMessage(),
+                'rewards' => []
+            ];
+        }
+    }
+
+    /**
+     * 标记奖励为已过期
+     *
+     * @param int $userId 用户ID
+     * @param int $activityId 活动ID
+     * @return bool
+     */
+    public static function markRewardAsExpired(int $userId, int $activityId): bool
+    {
+        try {
+            $rewardLogic = new RewardLogic();
+            return $rewardLogic->markRewardAsExpired($userId, $activityId);
+        } catch (Exception $e) {
+            Log::error('标记奖励为已过期失败', [
+                'user_id' => $userId,
+                'activity_id' => $activityId,
+                'error' => $e->getMessage()
+            ]);
+            return false;
+        }
+    }
+
+    /**
+     * 批量发放活动奖励
+     *
+     * @param array $userIds 用户ID数组
+     * @param int $activityId 活动ID
+     * @return array
+     */
+    public static function batchGrantActivityReward(array $userIds, int $activityId): array
+    {
+        $results = [
+            'success_count' => 0,
+            'fail_count' => 0,
+            'details' => []
+        ];
+        
+        foreach ($userIds as $userId) {
+            $result = self::grantActivityReward($userId, $activityId);
+            
+            if ($result['success']) {
+                $results['success_count']++;
+            } else {
+                $results['fail_count']++;
+            }
+            
+            $results['details'][$userId] = $result;
+        }
+        
+        return $results;
+    }
+}

+ 3 - 0
noai.md

@@ -66,3 +66,6 @@ AppGame模块,增加登陆成功事件
 改为被动重置,在任务需要更新或被使用的时候进行重置
 在更新进度时,根据 task_user_progress 的 last_update_time 可得知 本次进度增加是否需要重置 ;
 在任务获取是,根据 task_user_tasks  
+
+
+数据仓库(Repository)里不应该有任何方法,修复已创建的所有数据仓库,注意检查已经定义的方法是否被使用,如果没有使用,删除该方法