status == LotteryEnum::STATUS_ONGOING && $activity->start_time <= $now && $activity->end_time >= $now; } /** * 检查活动是否已结束 */ public static function isEnded(LotteryActivity $activity) { $now = time(); return $activity->status == LotteryEnum::STATUS_ENDED || $activity->end_time < $now; } /** * 检查活动是否未开始 */ public static function isNotStarted(LotteryActivity $activity) { $now = time(); return $activity->status == LotteryEnum::STATUS_NOT_STARTED && $activity->start_time > $now; } /** * 检查活动是否已暂停 */ public static function isSuspended(LotteryActivity $activity) { return $activity->status == LotteryEnum::STATUS_SUSPENDED; } /** * 检查活动是否已取消 */ public static function isCancelled(LotteryActivity $activity) { return $activity->status == LotteryEnum::STATUS_CANCELLED; } /** * 检查是否在抽奖时间内 * 注意:当前数据库表结构中没有draw_time相关字段,所以始终返回true */ public static function isInDrawTime(LotteryActivity $activity) { // 当前表结构中没有draw_time_enable, draw_time_start, draw_time_end字段 // 所以直接返回true,表示始终可以抽奖 return true; } /** * 获取正在进行的活动 */ public static function getRunningActivities() { $now = time(); return LotteryActivity::where('status', LotteryEnum::STATUS_ONGOING) ->where('start_time', '<=', $now) ->where('end_time', '>=', $now) ->select(); } /** * 获取未开始的活动 */ public static function getNotStartedActivities() { $now = time(); return LotteryActivity::where('status', LotteryEnum::STATUS_NOT_STARTED) ->where('start_time', '>', $now) ->select(); } /** * 获取已结束的活动 */ public static function getEndedActivities() { $now = time(); return LotteryActivity::where('status', LotteryEnum::STATUS_ENDED) ->orWhere('end_time', '<', $now) ->select(); } /** * 获取可显示的活动(排除逻辑状态) */ public static function getDisplayableActivities() { $displayableStatuses = array_keys(LotteryEnum::getActivityStatusMap()); return LotteryActivity::whereIn('status', $displayableStatuses)->select(); } /** * 验证活动状态是否有效 */ public static function isValidStatus(LotteryActivity $activity) { return LotteryEnum::isValidActivityStatus($activity->status); } /** * 验证开奖方式是否有效 */ public static function isValidLotteryType(LotteryActivity $activity) { return LotteryEnum::isValidLotteryType($activity->lottery_type); } /** * 获取活动状态描述 */ public static function getActivityStatusDescription(LotteryActivity $activity) { $now = time(); if (self::isCancelled($activity)) { return '活动已取消'; } if (self::isSuspended($activity)) { return '活动已暂停'; } if (self::isEnded($activity)) { return '活动已结束'; } if (self::isRunning($activity)) { return '活动进行中'; } if (self::isNotStarted($activity)) { return '活动未开始'; } return '未知状态'; } /** * 检查用户是否可以参与活动 */ public static function canUserParticipate(LotteryActivity $activity, $userId) { // 检查活动状态 if (!self::isRunning($activity)) { return false; } // 检查抽奖时间 if (!self::isInDrawTime($activity)) { return false; } // TODO: 检查用户群体限制 // TODO: 检查用户参与次数限制 return true; } /** * 获取活动统计信息 */ public static function getActivityStatistics(LotteryActivity $activity) { return [ 'total_participants' => $activity->drawRecords()->count(), 'total_winners' => $activity->winRecords()->count(), 'total_prizes' => $activity->prizes()->count(), 'total_conditions' => $activity->conditions()->count(), ]; } /** * 批量更新活动状态 */ public static function batchUpdateStatus() { $now = time(); // 将已过期的活动标记为已结束 LotteryActivity::where('status', LotteryEnum::STATUS_ONGOING) ->where('end_time', '<', $now) ->update(['status' => LotteryEnum::STATUS_ENDED]); // 将到期的未开始活动标记为进行中 LotteryActivity::where('status', LotteryEnum::STATUS_NOT_STARTED) ->where('start_time', '<=', $now) ->where('end_time', '>=', $now) ->update(['status' => LotteryEnum::STATUS_ONGOING]); } /** * 创建新活动 */ public static function createActivity($data) { // 验证数据 if (!LotteryEnum::isValidActivityStatus($data['status'])) { throw new \Exception('无效的活动状态'); } if (!LotteryEnum::isValidLotteryType($data['lottery_type'])) { throw new \Exception('无效的开奖方式'); } return LotteryActivity::create($data); } /** * 更新活动 */ public static function updateActivity(LotteryActivity $activity, $data) { // 验证数据 if (isset($data['status']) && !LotteryEnum::isValidActivityStatus($data['status'])) { throw new \Exception('无效的活动状态'); } if (isset($data['lottery_type']) && !LotteryEnum::isValidLotteryType($data['lottery_type'])) { throw new \Exception('无效的开奖方式'); } return $activity->save($data); } /** * 删除活动 */ public static function deleteActivity(LotteryActivity $activity) { // 检查是否可以删除 if (self::isRunning($activity)) { throw new \Exception('进行中的活动不能删除'); } return $activity->delete(); } /** * 获取奖品列表 * @param int|null $activityId 活动ID,不传则查询进行中活动的奖品 * @param int $page 页码 * @param int $pageSize 每页数量 * @param array|null $type 奖品类型筛选数组 * @return \think\Paginator */ public static function getPrizes($activityId = null, $page = 1, $pageSize = 10, $type = null) { $where = []; // 如果指定了活动ID,查询该活动的奖品 if ($activityId) { $where['activity_id'] = $activityId; } else { // 否则查询进行中活动的奖品 $now = time(); $runningActivityIds = LotteryActivity::where('status', LotteryEnum::STATUS_ONGOING) ->where('start_time', '<=', $now) ->where('end_time', '>=', $now) ->column('id'); if (empty($runningActivityIds)) { // 返回空的分页对象 $prizeModel = new \app\common\model\lottery\LotteryPrize(); return $prizeModel->where('id', 0)->paginate($pageSize, false, ['page' => $page]); } $where['activity_id'] = ['in', $runningActivityIds]; } // 奖品状态筛选(只查询有效的奖品) $where['status'] = 1; // 奖品类型筛选 if ($type && is_array($type) && !empty($type)) { $where['type'] = ['in', $type]; } // 使用模型的分页查询器 $prizeModel = new \app\common\model\lottery\LotteryPrize(); $paginate = $prizeModel->where($where) ->field('id,activity_id,name,type,image,description,probability,total_stock,remain_stock,win_prompt,sort_order,unlock_people_num,createtime') ->order('sort_order asc, createtime desc') ->paginate($pageSize, false, ['page' => $page]); // 处理分页数据,添加额外信息 foreach ($paginate->items() as $prize) { // 获取活动信息 $activity = LotteryActivity::find($prize->activity_id); $prize->activity_name = $activity->name ?? ''; $prize->activity_status = $activity->status ?? 0; // 奖品类型文本 $prize->type_text = LotteryEnum::getPrizeTypeText($prize->type); // 检查奖品是否已解锁(如果活动开启按人数解锁) if ($activity && $activity->unlock_by_people && $prize->unlock_people_num) { $currentPeopleCount = \app\common\Service\lottery\LotteryChanceService::getActivityParticipants($prize->activity_id); $prize->is_unlocked = $currentPeopleCount >= $prize->unlock_people_num; } else { $prize->is_unlocked = true; } // 计算中奖率百分比 $prize->probability_percent = round($prize->probability * 100, 2); // 计算库存百分比 if ($prize->total_stock > 0) { $prize->stock_percent = round(($prize->remain_stock / $prize->total_stock) * 100, 2); } else { $prize->stock_percent = 0; } } return $paginate; } /** * 获取活动奖品统计信息 * @param int $activityId 活动ID * @return array */ public static function getActivityPrizeStats($activityId) { $prizes = \app\common\model\lottery\LotteryPrize::where('activity_id', $activityId) ->where('status', 1) ->select(); $stats = [ 'total_prizes' => 0, 'total_stock' => 0, 'remain_stock' => 0, 'used_stock' => 0, 'prize_types' => [], 'unlocked_prizes' => 0, 'locked_prizes' => 0 ]; foreach ($prizes as $prize) { $stats['total_prizes']++; $stats['total_stock'] += $prize->total_stock; $stats['remain_stock'] += $prize->remain_stock; $stats['used_stock'] += ($prize->total_stock - $prize->remain_stock); // 统计奖品类型 $typeText = LotteryEnum::getPrizeTypeText($prize->type); if (!isset($stats['prize_types'][$prize->type])) { $stats['prize_types'][$prize->type] = [ 'type' => $prize->type, 'type_text' => $typeText, 'count' => 0, 'total_stock' => 0, 'remain_stock' => 0 ]; } $stats['prize_types'][$prize->type]['count']++; $stats['prize_types'][$prize->type]['total_stock'] += $prize->total_stock; $stats['prize_types'][$prize->type]['remain_stock'] += $prize->remain_stock; // 检查解锁状态 $activity = LotteryActivity::find($activityId); if ($activity && $activity->unlock_by_people && $prize->unlock_people_num) { $currentPeopleCount = \app\common\Service\lottery\LotteryChanceService::getActivityParticipants($activityId); if ($currentPeopleCount >= $prize->unlock_people_num) { $stats['unlocked_prizes']++; } else { $stats['locked_prizes']++; } } else { $stats['unlocked_prizes']++; } } return $stats; } /** * 获取进行中活动的奖品列表 * @param int $page 页码 * @param int $pageSize 每页数量 * @param int|array|null $type 奖品类型筛选,支持单个类型或类型数组 * @return \think\Paginator */ public static function getRunningActivityPrizes($page = 1, $pageSize = 20, $type = null) { return self::getPrizes(null, $page, $pageSize, $type); } /** * 获取指定活动的奖品列表 * @param int $activityId 活动ID * @param int $page 页码 * @param int $pageSize 每页数量 * @param int|array|null $type 奖品类型筛选,支持单个类型或类型数组 * @return \think\Paginator */ public static function getActivityPrizes($activityId, $page = 1, $pageSize = 20, $type = null) { return self::getPrizes($activityId, $page, $pageSize, $type); } }