消耗活动菜单 public function checkAuth($auth) { $campaign = model('ChannelSpecialManage')->isWhite('campaign', $auth); if ($campaign){ return '/admin/campaign/read'; } $card = model('ChannelSpecialManage')->isWhite('cardflip', $auth); if ($card){ return '/admin/card/flip'; } return ''; } /** * 后台 消耗活动-翻牌、读书 权限 * @param $group * @param $auth * @return array */ public function getAuth($group,$auth) { $camAuth = ['campaign','cardflip']; if ( in_array($group,[1,2,6]) ){ return $camAuth; } $campaign = model('ChannelSpecialManage')->isWhite('campaign', $auth); if (!$campaign){ unset($camAuth[0]); } $card = model('ChannelSpecialManage')->isWhite('cardflip', $auth); if (!$card){ unset($camAuth[1]); } return $camAuth; } /** * @param $actId * @return array */ public function winList($actId) { $redisKey = ActivityConstants::CARD_AWARD_WIN_LIST.$actId; $redislist = Redis::instance()->lRange($redisKey,0,-1); $res = []; foreach ($redislist as $k=>$v){ $res[] = json_decode($v,true); } unset($redislist); return $res; } /** * 获取本次活动的详情-后台刷到redis * @param $id * @return array */ public function getCardInfo($id) { $redisKey = ActivityConstants::CARD_FLIP_INFO.$id; $cardInfo = Redis::instance()->hGetAll($redisKey); return $cardInfo; } /** * 查看用户是否在用户组中 * @param $userGroupId * @param $userInfo * @return bool */ public function checkUserAuth($userGroupId,$userInfo) { return true; $redisKey = ActivityConstants::USER_GROUP_SET.$userGroupId.$userInfo->channel_id; $isHave = Redis::instance()->sIsMember($redisKey,$userInfo->id); return (bool)$isHave; } /** * 获取banner * @param $userInfo * @return array|mixed */ public function getBannerImage($userInfo) { return [];//去掉banner图 $redisKey = ActivityConstants::CARD_FLIP_LISTS; $list = Redis::instance()->sMembers($redisKey); if (empty($list)){ return []; } foreach ($list as $k=>$v){ $temp = json_decode($v,true); if ($temp['end_time'] < time()){ continue; } if ($this->checkUserAuth($temp['group_id'],$userInfo)){ return $temp; }; } return []; } /** * @param $actId * @return array */ public function getCardAwardList($actId) { $redisKey = ActivityConstants::CARD_FLIP_AWARD_LIST.$actId; $list = Redis::instance()->sMembers($redisKey); $res = []; if (empty($list)){ return []; } $awardList = $this->getAwardList(); if (empty($awardList)){ return []; } foreach ($list as $k =>$v){ $temp = json_decode($v,true); $award = $awardList[$temp['a_id']] ?? []; $temp['image'] = $award['image'] ?? ''; $temp['type'] = $award['type'] ?? ''; $temp['content'] = $award['content'] ?? ''; $res[] = $temp; } return $res; } /** * 奖品库 * @return array */ public function getAwardList() { $redisKey = ActivityConstants::AWARD_LIST_SET; $list = Redis::instance()->sMembers($redisKey); $res = []; if(!empty($list))foreach ($list as $k=>$v){ $temp = json_decode($v,true); $res[$temp['id']] = $temp; } return $res; } /** * 获取我的奖品列表 * @param $actId * @param $userId * @return array */ public function getMyAward($actId,$userId) { $redisKey = ActivityConstants::CARD_USER_AWARD_LIST.$userId.':'.$actId; $list = Redis::instance()->sMembers($redisKey); $res = []; if (!$list){ $dbList = model('CardLog')->where(['c_id'=>$actId,'user_id'=>$userId,'state'=>1])->order('createtime','desc')->limit(30)->select(); $rdList = []; if ($dbList){ foreach ($dbList as $k=>$v){ $rdList[] = json_encode($v); } }else{ $rdList[] = json_encode(['id'=>0]); } Redis::instance()->sAddArray($redisKey,$rdList); Redis::instance()->expire($redisKey,86400); $res = (array)$dbList; }else{ foreach ($list as $kk =>$vv){ $temp = json_decode($vv,true); if ($temp['id'] == 0){ continue; } $res[] = $temp; } } return $res; } /** * @param $actId * @param $userInfo * @return array|bool|mixed * @throws \think\Exception */ public function lottery($actId,$userInfo) { //获取活动 $res = ['code'=>1,'msg'=>'','data'=>[]]; $cardInfo = $this->getCardInfo($actId); if (empty($cardInfo) || $cardInfo['begin_time'] > time() || $cardInfo['end_time'] < time()){ $res['code'] = 0; $res['msg'] = '活动未开始'; return $res; } $consumeKandian = 0; //用户今天的抽奖次数加一 $isLimit = $this->incrLimit($cardInfo,$userInfo->id); if (!$isLimit){ $res['code'] = 2; $res['msg'] = '今天抽奖次数达到'.$cardInfo['limit'].',明日再来!'; return $res; } //是否消费成功的标识 $isConsume = false; //扣减抽奖次数 if ($this->getDrawNum($actId,$userInfo->id)){ $isConsume = $this->decrDrawsNum($actId,$userInfo->id); } //获取用户的书币数 if (!$isConsume){ $obj = FinancialService::instance()->getTotalKandianAndFreeKandian($userInfo->id); if ($cardInfo['kandian'] > $obj->data){ $res['code'] = 3; $res['msg'] = '书币不足'; $this->decrLimit($cardInfo,$userInfo->id); return $res; } //扣减书币 $isConsume = $this->cardConsumeKandian($userInfo->id,$cardInfo); $consumeKandian = $cardInfo['kandian']; } //消费失败 退回抽奖次数 if (!$isConsume){ $this->decrLimit($cardInfo,$userInfo->id); } $awardInfo = []; //如果消费成功,随机获取奖品 if ($isConsume){ $awardId = $this->getAwardId($actId); $awardInfo = $this->getCardAwardOne($actId,$awardId); //给用户分配奖品 if ($awardInfo){ $awardInfo = $this->setUserAward($awardInfo,$userInfo,$cardInfo); } //打点pv uv $this->sendDraws($cardInfo['id'],$userInfo); if ($consumeKandian){//消耗看点的打点 $this->sendKandian($cardInfo['id'],$userInfo,$consumeKandian); } } if (!$awardInfo){ $awardInfo['id'] = $userInfo->id; $awardInfo['name'] = '未中奖'; $awardInfo['image'] = cdnurl('/assets/img/frontend/activity/card/result-thank.png'); $awardInfo['type'] = 1; LogService::info('翻牌活动-抽奖异常'.$userInfo->id); } $res['data'] = $awardInfo; return $res; } /** * 获取当前用户的抽奖次数 * @param $actId * @param $userId * @return int */ public function getDrawNum($actId,$userId) { $redisKey = ActivityConstants::CARD_USER_DRAWS_NUM.$actId.$userId; return (int)Redis::instance()->get($redisKey); } /** * 增加抽奖次数 * @param $actId * @param $userId * @param $ttl * @return bool */ private function incrDrawsNum($actId,$userId,$ttl) { $redisKey = ActivityConstants::CARD_USER_DRAWS_NUM.$actId.$userId; if(Redis::instance()->exists($redisKey)){ Redis::instance()->incr($redisKey); }else{ Redis::instance()->setex($redisKey,$ttl,1); } LogService::info('翻牌活动-分配奖励-再来一次'.$redisKey); return true; } /** * 扣除抽奖次数 * @param $actId * @param $userId * @return bool */ private function decrDrawsNum($actId,$userId) { $redisKey = ActivityConstants::CARD_USER_DRAWS_NUM.$actId.$userId; $re = Redis::instance()->decr($redisKey); if ($re < 0){ Redis::instance()->del($redisKey); return false; } return true; } /** * 查看用户今天的抽奖次数 * @param $cardInfo * @param $userId * @return bool */ private function incrLimit($cardInfo,$userId) { if ($cardInfo['limit'] <= 0){ return true; } $redisKey = ActivityConstants::CARD_USER_LAST_NUM.$cardInfo['id'].':'.date('Ymd',time()).':'.$userId; $limitNum = (int)Redis::instance()->get($redisKey); if ($limitNum >= $cardInfo['limit']){ return false; } $re = Redis::instance()->incr($redisKey); if ($re == 1){//第一次 Redis::instance()->expire($redisKey,86400); } return true; } /** * 消费失败-退回用户抽奖次数 * @param $cardInfo * @param $userId * @return bool */ private function decrLimit($cardInfo,$userId) { if ($cardInfo['limit'] <= 0){ return true; } $redisKey = ActivityConstants::CARD_USER_LAST_NUM.$cardInfo['id'].':'.date('Ymd',time()).':'.$userId; Redis::instance()->decr($redisKey); return true; } /** * 翻牌活动的消费 * @param $userId * @param $cardInfo * @return bool */ private function cardConsumeKandian($userId,$cardInfo) { UserDdFlushService::instance()->checkUserFlushState($userId); //扣除永久书币 $res = FinancialService::instance()->payKandian($cardInfo['kandian'], $userId, '翻牌活动-抽奖'); if ( $res->code == 0 ) { // 增加消费记录 $campJson = json_encode([ 'card_id' => (int)$cardInfo['id'], 'name' => $cardInfo['name'], ]); $consumeData = [ 'user_id' => (int)$userId, 'type' => 3, 'chapter_name' => '', 'free_kandian'=>$res->data['free_kandian'], 'dd_free_kandian'=>$res->data['dd_free_kandian'], 'kandian' => $res->data['kandian'], 'dd_kandian' => $res->data['dd_kandian'], 'createtime' => time(), 'updatetime' => time(), 'camp_info' => $campJson, ]; FinancialService::instance()->getConsumeModel()->setConnect($userId)->insert($consumeData); LogService::info('翻牌活动消费成功'.$userId); return true; } LogService::info('翻牌活动消费失败'.json_decode($res)); return false; } /** * 抽奖动作 返回中奖的奖品ID * @param $actId * @return int */ private function getAwardId($actId) { if (empty($actId)){ return 0; } $codeRedisKey = ActivityConstants::CARD_AWARD_CODES.$actId; $codes = Redis::instance()->hGetAll($codeRedisKey); if (empty($codes)){ return 0; } $userCode = rand(0,100); $userAward = 0; ksort($codes); foreach ($codes as $k=>$v){ if ($k >= $userCode){ $userAward = $v; break; } } LogService::info('翻牌活动-中奖种子:'.$userCode.'--'.json_encode($userAward)); return (int)$userAward; } /** * @param $actId * @param $id * @return array|mixed * @throws \think\Exception */ private function getCardAwardOne($actId,$awardId) { $list = $this->getCardAwardList($actId); $cardAwardList = array_column($list,null,'id'); return $cardAwardList[$awardId] ?? []; } /** * 赠送奖品 * @param $awardInfo * @param $userInfo * @param $cardInfo * @return array|bool */ private function setUserAward($awardInfo,$userInfo,$cardInfo) { $type = $awardInfo['type']; $insert = []; $res = [ 'id'=>$userInfo->id, 'image'=>$awardInfo['image'], 'name'=>$awardInfo['show_name'], 'type'=>$type, ]; $isGet = true; switch ($type){ case 1: //无奖励 break; case 2: $bookInfo = $this->addBook($userInfo->id,$awardInfo); if ($bookInfo){ $insert['show_name'] = $bookInfo['name']; $insert['book_id'] = $bookInfo['id']; $res['name'] = $bookInfo['name']; break; } $isGet = false; break; case 3: //赠送vip $isGet = $this->editVipTime($userInfo,(int)$awardInfo['content']); // $insert['book_id'] = (int)$awardInfo['content']; break; case 4: //赠送书币 $kandian = (int)$awardInfo['content']; $obj = FinancialService::instance()->modifyUserKandian($userInfo->id,1,1,0,$kandian,'翻牌活动赠送',1); $isGet = $obj->code == 0 ? true : false; $res['kandian'] = $kandian; break; case 5: //抽奖次数 $ttl = $cardInfo['end_time'] - time(); $isGet = $this->incrDrawsNum($awardInfo['c_id'], $userInfo->id, $ttl); break; default: break; } if (!$isGet){ LogService::info('翻牌活动-分配奖励异常'.json_encode($cardInfo)); return false; } LogService::info('翻牌活动-分配奖励成功'.$type); if (in_array( $type,[2,3,4]) ){ $insert['user_id'] = $userInfo->id; $insert['state'] = 1; $insert['show_name'] = $insert['show_name'] ?? $awardInfo['show_name']; $insert['c_id'] = $awardInfo['c_id']; $insert['a_id'] = $awardInfo['a_id']; $insert['create_date'] = date('Ymd',time()); $insert['createtime'] = time(); $insert['success_time'] = 0; $insert['id'] = model('CardLog')->insertGetId($insert); //插入缓存 $redisKey = ActivityConstants::CARD_USER_AWARD_LIST.$userInfo->id.':'.$awardInfo['c_id']; Redis::instance()->del($redisKey); $redisKey = ActivityConstants::CARD_AWARD_WIN_LIST.$awardInfo['c_id']; $userList['name'] = $insert['show_name']; $userList['id'] = $this->hideUserId($userInfo->id); Redis::instance()->rPush($redisKey,json_encode($userList)); Redis::instance()->lpop($redisKey); } return $res; } private function hideUserId(string $userId) { for ($i = 3;$i<6;$i++){ if (!isset($userId[$i])){ break; } $userId[$i] = '*'; } return $userId; } /** * 增送vip * @param $userInfo * @param $awardInfo * @return bool */ private function editVipTime($userInfo,$days,$type=6,$notes='翻牌活动赠送') { $saveDate = []; //新增充值记录 $userDate = []; //修改用户数据 $userDate['id'] = $userInfo->id; $saveDate['user_id'] = $userInfo->id; $saveDate['type'] = $type; $saveDate['notes'] = $notes; $saveDate['edit_type'] = 1; $saveDate['createtime'] = time(); $saveDate['day'] = $days; if(intval($userInfo->vip_endtime)>time()){ $userDate['vip_endtime'] = $days*86400 + intval($userInfo->vip_endtime); $saveDate['vip_starttime'] = intval($userInfo->vip_endtime); }else{ $userDate['vip_endtime'] = $days*86400 +time(); $saveDate['vip_starttime'] = time(); } $saveDate['vip_starttime'] = model('Recharge')->getVipStartTime($userInfo->id); $saveDate['channel_vip_starttime'] = model('Recharge')->getChannelVipStartTime($userInfo->id); if (ApiService::instance()->checkApiOn()) { $userUpdate = new UserUpdate(); $userUpdate->setId($userInfo->id); $userUpdate->setAddvipday($days * 86400); \app\source\service\UserService::instance()->updateUser($userUpdate); } else { $flagUser = model('User')->setConnect($userInfo->id)->update($userDate); //更改用户表数据 } //user加入redis缓存 $userKey = 'UN:'.$userInfo->id; Redis::instance()->del($userKey); $flagRecharge = model('Recharge')->setConnect($userInfo->id)->insert($saveDate); //插入充值记录 if(!$flagRecharge){ return false; } return true; } /** * 赠送书籍 * @param $userId * @param $awardInfo * @return array|bool */ private function addBook($userId,$awardInfo) { //获取书籍ID $bookIds = explode(',', $awardInfo['content']); //查看用户已经购买的书 $existBookIds = FinancialService::instance()->getConsumeModel()->setConnect($userId) ->field('book_id') ->where('user_id', $userId) ->where('type', BookConstants::BOOK_BILLING_MODEL_BOOK) ->select(); if ($existBookIds) { $existBookIds = array_column($existBookIds, 'book_id'); } $bookIds = array_diff($bookIds, $existBookIds); if (!$bookIds) { return false; } $bookId = $bookIds[array_rand($bookIds)]; $bookInfo = model('Book')->BookInfo($bookId); if (empty($bookInfo)) { LogService::info('添加的数据信息有误' . $bookId); return false; } BuyMoreService::instance()->addFreeBook($userId, $bookId); return $bookInfo; } public function getCardFlipPvKey($actId, $adminId, $date = null) { $date = empty($date) ? date('Ymd') : $date; return sprintf('PVCF:%s:%s:%s', $date, $adminId, $actId); } public function getCardFlipUvKey($actId, $adminId, $date = null) { $date = empty($date) ? date('Ymd') : $date; return sprintf('UVCF:%s:%s:%s', $date, $adminId, $actId); } public function getCardFlipDrawsPvKey($actId, $adminId, $date = null) { $date = empty($date) ? date('Ymd') : $date; return sprintf('PVCFD:%s:%s:%s', $date, $adminId, $actId); } public function getCardFlipDrawsUvKey($actId, $adminId, $date = null) { $date = empty($date) ? date('Ymd') : $date; return sprintf('UVCFD:%s:%s:%s', $date, $adminId, $actId); } public function getCardFlipKandianKey($actId, $adminId, $date = null) { $date = empty($date) ? date('Ymd') : $date; return sprintf('CFKD:%s:%s:%s', $date, $adminId, $actId); } /** * 展示打点 * @param $actId * @param $userInfo */ public function sendShow($actId, $userInfo) { $timeOutStamp = strtotime(date('Y-m-d 01:00:00', strtotime('+1 day'))); $userInfo = UserService::instance()->getUserInfo(); $channelId = $userInfo->channel_id; $userId = $userInfo->id; #region PV $wholePvKey = $this->getCardFlipPvKey($actId, 0); Redis::instance()->incr($wholePvKey); Redis::instance()->expireAt($wholePvKey, $timeOutStamp); $adminPvKey = $this->getCardFlipPvKey($actId, $channelId); Redis::instance()->incr($adminPvKey); Redis::instance()->expireAt($adminPvKey, $timeOutStamp); #endregion #region UV $wholeUvKey = $this->getCardFlipUvKey($actId, 0); Redis::instance()->pfAdd($wholeUvKey, $userId); Redis::instance()->expireAt($wholeUvKey, $timeOutStamp); $adminUvKey = $this->getCardFlipUvKey($actId, $channelId); Redis::instance()->pfAdd($adminUvKey, $userId); Redis::instance()->expireAt($adminUvKey, $timeOutStamp); #endregion } /** * 抽奖打点 * @param $actId * @param $userInfo */ private function sendDraws($actId, $userInfo) { $timeOutStamp = strtotime(date('Y-m-d 01:00:00', strtotime('+1 day'))); $userInfo = UserService::instance()->getUserInfo(); $channelId = $userInfo->channel_id; $userId = $userInfo->id; #region PV $wholePvKey = $this->getCardFlipDrawsPvKey($actId, 0); Redis::instance()->incr($wholePvKey); Redis::instance()->expireAt($wholePvKey, $timeOutStamp); $adminPvKey = $this->getCardFlipDrawsPvKey($actId, $channelId); Redis::instance()->incr($adminPvKey); Redis::instance()->expireAt($adminPvKey, $timeOutStamp); #endregion #region UV $wholeUvKey = $this->getCardFlipDrawsUvKey($actId, 0); Redis::instance()->pfAdd($wholeUvKey, $userId); Redis::instance()->expireAt($wholeUvKey, $timeOutStamp); $adminUvKey = $this->getCardFlipDrawsUvKey($actId, $channelId); Redis::instance()->pfAdd($adminUvKey, $userId); Redis::instance()->expireAt($adminUvKey, $timeOutStamp); #endregion } /** *抽奖消耗看点打点 * @param $actId * @param $userInfo * @param int $kandian */ private function sendKandian($actId, $userInfo, $kandian = 0) { $timeOutStamp = strtotime(date('Y-m-d 01:00:00', strtotime('+1 day'))); $channelId = $userInfo->channel_id; $wholeKey = $this->getCardFlipKandianKey($actId, 0); Redis::instance()->incrBy($wholeKey, $kandian); Redis::instance()->expireAt($wholeKey, $timeOutStamp); $adminKey = $this->getCardFlipKandianKey($actId, $channelId); Redis::instance()->incrBy($adminKey, $kandian); Redis::instance()->expireAt($adminKey, $timeOutStamp); } }