LotteryChanceService.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. <?php
  2. namespace app\common\Service;
  3. use app\common\model\lottery\LotteryActivity;
  4. use app\common\model\lottery\LotteryCondition;
  5. use app\common\model\lottery\LotteryUserChance;
  6. use app\common\model\lottery\LotteryDrawRecord;
  7. use think\Exception;
  8. /**
  9. * 抽奖机会服务类
  10. * 处理用户获得抽奖机会的逻辑
  11. */
  12. class LotteryChanceService
  13. {
  14. /**
  15. * 订单完成后检查并分发抽奖机会
  16. * @param array $orderInfo 订单信息
  17. * @param int $userId 用户ID
  18. * @return array 获得的抽奖机会信息
  19. */
  20. public static function checkAndGrantChanceForOrder($orderInfo, $userId)
  21. {
  22. $grantedChances = [];
  23. // 获取所有正在进行的抽奖活动
  24. $activities = LotteryActivity::getRunningActivities();
  25. foreach ($activities as $activity) {
  26. try {
  27. $chances = static::processActivityForOrder($activity, $orderInfo, $userId);
  28. if ($chances > 0) {
  29. $grantedChances[] = [
  30. 'activity_id' => $activity->id,
  31. 'activity_name' => $activity->name,
  32. 'chances' => $chances
  33. ];
  34. }
  35. } catch (Exception $e) {
  36. // 记录错误但不影响其他活动的处理
  37. trace('抽奖机会分发失败: ' . $e->getMessage(), 'error');
  38. }
  39. }
  40. return $grantedChances;
  41. }
  42. /**
  43. * 充值完成后检查并分发抽奖机会
  44. * @param array $rechargeInfo 充值信息
  45. * @param int $userId 用户ID
  46. * @return array 获得的抽奖机会信息
  47. */
  48. public static function checkAndGrantChanceForRecharge($rechargeInfo, $userId)
  49. {
  50. $grantedChances = [];
  51. // 获取所有正在进行的抽奖活动
  52. $activities = LotteryActivity::getRunningActivities();
  53. foreach ($activities as $activity) {
  54. try {
  55. $chances = static::processActivityForRecharge($activity, $rechargeInfo, $userId);
  56. if ($chances > 0) {
  57. $grantedChances[] = [
  58. 'activity_id' => $activity->id,
  59. 'activity_name' => $activity->name,
  60. 'chances' => $chances
  61. ];
  62. }
  63. } catch (Exception $e) {
  64. // 记录错误但不影响其他活动的处理
  65. trace('抽奖机会分发失败: ' . $e->getMessage(), 'error');
  66. }
  67. }
  68. return $grantedChances;
  69. }
  70. /**
  71. * 处理订单相关的活动
  72. */
  73. private static function processActivityForOrder($activity, $orderInfo, $userId)
  74. {
  75. // 检查用户是否符合活动参与资格
  76. if (!static::checkUserQualification($activity, $userId)) {
  77. return 0;
  78. }
  79. // 获取活动的参与条件
  80. $conditions = LotteryCondition::getValidConditions($activity->id);
  81. $totalChances = 0;
  82. foreach ($conditions as $condition) {
  83. // 跳过充值条件
  84. if ($condition->type == LotteryCondition::TYPE_RECHARGE) {
  85. continue;
  86. }
  87. $chances = static::processConditionForOrder($condition, $orderInfo, $userId);
  88. $totalChances += $chances;
  89. }
  90. // 如果获得了抽奖机会,记录到数据库
  91. if ($totalChances > 0) {
  92. static::grantChanceToUser($activity->id, $userId, $totalChances, [
  93. 'trigger_type' => 'order',
  94. 'order_id' => $orderInfo['id'] ?? 0,
  95. 'order_amount' => $orderInfo['total_amount'] ?? 0,
  96. 'granted_time' => time()
  97. ]);
  98. }
  99. return $totalChances;
  100. }
  101. /**
  102. * 处理充值相关的活动
  103. */
  104. private static function processActivityForRecharge($activity, $rechargeInfo, $userId)
  105. {
  106. // 检查用户是否符合活动参与资格
  107. if (!static::checkUserQualification($activity, $userId)) {
  108. return 0;
  109. }
  110. // 获取活动的参与条件
  111. $conditions = LotteryCondition::getValidConditions($activity->id);
  112. $totalChances = 0;
  113. foreach ($conditions as $condition) {
  114. // 只处理充值条件
  115. if ($condition->type != LotteryCondition::TYPE_RECHARGE) {
  116. continue;
  117. }
  118. $chances = static::processConditionForRecharge($condition, $rechargeInfo, $userId);
  119. $totalChances += $chances;
  120. }
  121. // 如果获得了抽奖机会,记录到数据库
  122. if ($totalChances > 0) {
  123. static::grantChanceToUser($activity->id, $userId, $totalChances, [
  124. 'trigger_type' => 'recharge',
  125. 'recharge_amount' => $rechargeInfo['amount'] ?? 0,
  126. 'granted_time' => time()
  127. ]);
  128. }
  129. return $totalChances;
  130. }
  131. /**
  132. * 处理订单条件
  133. */
  134. private static function processConditionForOrder($condition, $orderInfo, $userId)
  135. {
  136. $chances = 0;
  137. switch ($condition->type) {
  138. case LotteryCondition::TYPE_GOODS:
  139. if ($condition->validateOrder($orderInfo)) {
  140. $chances = $condition->getRewardTimes();
  141. }
  142. break;
  143. case LotteryCondition::TYPE_ORDER_AMOUNT:
  144. if ($condition->validateOrder($orderInfo)) {
  145. $chances = $condition->getRewardTimes();
  146. // 如果可重复获得,根据金额倍数计算次数
  147. if ($condition->canRepeat()) {
  148. $multiple = floor($orderInfo['total_amount'] / $condition->condition_value);
  149. $chances *= $multiple;
  150. }
  151. }
  152. break;
  153. case LotteryCondition::TYPE_ACCUMULATE:
  154. if ($condition->validateAccumulateCondition($userId, $condition->activity_id)) {
  155. // 检查是否已经因为累计消费获得过机会
  156. if (!static::hasGrantedForAccumulate($condition->activity_id, $userId)) {
  157. $chances = $condition->getRewardTimes();
  158. }
  159. }
  160. break;
  161. }
  162. return $chances;
  163. }
  164. /**
  165. * 处理充值条件
  166. */
  167. private static function processConditionForRecharge($condition, $rechargeInfo, $userId)
  168. {
  169. $chances = 0;
  170. if ($condition->validateOrder(['type' => 'recharge', 'amount' => $rechargeInfo['amount']])) {
  171. $chances = $condition->getRewardTimes();
  172. // 如果可重复获得,根据金额倍数计算次数
  173. if ($condition->canRepeat()) {
  174. $multiple = floor($rechargeInfo['amount'] / $condition->condition_value);
  175. $chances *= $multiple;
  176. }
  177. }
  178. return $chances;
  179. }
  180. /**
  181. * 检查用户资格
  182. */
  183. private static function checkUserQualification($activity, $userId)
  184. {
  185. // 检查用户群体限制
  186. switch ($activity->user_limit_type) {
  187. case LotteryActivity::USER_LIMIT_ALL:
  188. return true;
  189. case LotteryActivity::USER_LIMIT_LEVEL:
  190. return static::checkUserLevel($userId, $activity->user_limit_value);
  191. case LotteryActivity::USER_LIMIT_TAG:
  192. return static::checkUserTag($userId, $activity->user_limit_value);
  193. default:
  194. return false;
  195. }
  196. }
  197. /**
  198. * 检查用户等级
  199. */
  200. private static function checkUserLevel($userId, $limitValue)
  201. {
  202. if (empty($limitValue)) {
  203. return true;
  204. }
  205. $user = \app\common\model\User::find($userId);
  206. return $user && in_array($user->level, (array)$limitValue);
  207. }
  208. /**
  209. * 检查用户标签
  210. */
  211. private static function checkUserTag($userId, $limitValue)
  212. {
  213. if (empty($limitValue)) {
  214. return true;
  215. }
  216. // 这里需要根据实际的用户标签系统实现
  217. // 暂时返回true
  218. return true;
  219. }
  220. /**
  221. * 检查是否已因累计消费获得过机会
  222. */
  223. private static function hasGrantedForAccumulate($activityId, $userId)
  224. {
  225. $userChance = LotteryUserChance::getUserChance($activityId, $userId);
  226. if (!$userChance) {
  227. return false;
  228. }
  229. $getDetail = $userChance->get_detail_data;
  230. foreach ($getDetail as $detail) {
  231. if (($detail['trigger_type'] ?? '') === 'accumulate') {
  232. return true;
  233. }
  234. }
  235. return false;
  236. }
  237. /**
  238. * 给用户分发抽奖机会
  239. */
  240. private static function grantChanceToUser($activityId, $userId, $chances, $detail)
  241. {
  242. return LotteryUserChance::addChance($activityId, $userId, $chances, $detail);
  243. }
  244. /**
  245. * 手动给用户增加抽奖机会(管理员操作)
  246. * @param int $activityId 活动ID
  247. * @param int $userId 用户ID
  248. * @param int $chances 机会次数
  249. * @param string $reason 原因
  250. * @param int $adminId 管理员ID
  251. * @return bool
  252. */
  253. public static function manualGrantChance($activityId, $userId, $chances, $reason, $adminId)
  254. {
  255. $activity = LotteryActivity::find($activityId);
  256. if (!$activity) {
  257. throw new Exception('活动不存在');
  258. }
  259. $detail = [
  260. 'trigger_type' => 'manual',
  261. 'reason' => $reason,
  262. 'admin_id' => $adminId,
  263. 'granted_time' => time()
  264. ];
  265. return static::grantChanceToUser($activityId, $userId, $chances, $detail);
  266. }
  267. /**
  268. * 获取用户在指定活动中的抽奖机会详情
  269. * @param int $activityId 活动ID
  270. * @param int $userId 用户ID
  271. * @return array
  272. */
  273. public static function getUserChanceDetail($activityId, $userId)
  274. {
  275. $userChance = LotteryUserChance::getUserChance($activityId, $userId);
  276. if (!$userChance) {
  277. return [
  278. 'total_chances' => 0,
  279. 'used_chances' => 0,
  280. 'remain_chances' => 0,
  281. 'get_detail' => []
  282. ];
  283. }
  284. return [
  285. 'total_chances' => $userChance->total_chances,
  286. 'used_chances' => $userChance->used_chances,
  287. 'remain_chances' => $userChance->remain_chances,
  288. 'last_get_time' => $userChance->last_get_time,
  289. 'last_use_time' => $userChance->last_use_time,
  290. 'get_detail' => $userChance->get_detail_data
  291. ];
  292. }
  293. /**
  294. * 批量初始化用户抽奖机会(活动开始时)
  295. * @param int $activityId 活动ID
  296. * @param array $userIds 用户ID数组
  297. * @param int $initChances 初始机会数
  298. * @return bool
  299. */
  300. public static function batchInitChances($activityId, $userIds, $initChances = 1)
  301. {
  302. $activity = LotteryActivity::find($activityId);
  303. if (!$activity) {
  304. throw new Exception('活动不存在');
  305. }
  306. return LotteryUserChance::batchCreateChances($activityId, $userIds, $initChances);
  307. }
  308. }