PHP YII 抽奖接口,大转盘抽奖 抽奖代码 【附源码+完整版】


/**
 * Class LotteryController
 * AppLication: LotteryController
 * Author:C
 * @param eid,userid,token
 * Time: 10:28
 */

class LotteryController extends BaseLotteryController
{
	//点进之后某一个的数据展示
    public function actionIndex()
    {
        $json = $this->json;
        self::isRequired(array('userid','eid','prizeid'), true);
        // 抽奖id的值 $jison['prizeid'];
        $sql = 'select award_name,frequency,consume_score,prize,`explain`,start_time,end_time,luck_draw_num,luckDrawProbability,switch, obj_type from {{prize_configure}}  where id ='.$json['prizeid'];
        $param = Yii::app()->db->createCommand($sql)->queryRow();
        $record = @json_decode($param['prize'], true);
        if(empty($record)){
           self::errmsg('参数错误');
        }
        $colunmId = array_column($record,'goodsid');
        $colunmIds = implode(',',$colunmId);
        $sqlOne = "select id,`img` from {{goods}} where id  in($colunmIds)";
        $result = Yii::app()->db->createCommand($sqlOne)->queryAll();
        foreach ($result as $key => $value){
             foreach($record as $k => $val){
                 if($val['goodsid'] == $value['id']){
                     $arr = explode(',',$value['img']);
                     $current  =  current($arr);
                     $record[$k]['img'] = $this->attachmentUrl($current);
                 }
             }
         }
        $thankNum = [];
          foreach($record as $key => $val){
              $thankNum[$key] = $val['prob'];
          }
          $thankNums = 6 - count($record); //谢谢参与的个数
          $array = [];
          for ($i = 0;$i < $thankNums;$i++){
              $array = [
                  $i =>[
                      'goodsid'=>'',
                      'prob'=>floatval(100-array_sum($thankNum))/$thankNums,
                      'name'=>'谢谢参与'
                  ]
              ];
          }
         $record = array_merge($record,$array);
         shuffle($record);
         $row['data'] = array(
             'lotteryList' => $record,
             'info' => array(
                 'start_time' => !empty($param['start_time']) ? date("Y-m-d H:i:s",$param['start_time']) : '',
                 'end_time' => !empty($param['end_time'])? date('Y-m-d H:i:s',$param['end_time']) : '',
                 'frequency' => $param['frequency'],
                 'consume_score' => $param['consume_score'],
                 'explain' => $param['explain'],
                 'scoreName' =>Score::getIntegralCustom($this->eid),
                 'award_name' =>$param['award_name'],
             )
         );
         self::echojson($row);
    }

抽奖 开始代码

PHP YII 抽奖接口,大转盘抽奖 抽奖代码 【附源码+完整版】_第1张图片

    public function  actionLuck()
    {
        $json = $this->json;
        self::isRequired(array('userid', 'eid','prizeid'), true);
        $lotteryData = Lottery::model()->findByPk($json['prizeid']); 
		$config = [
		'json' => $json,
		'eid' => $this->eid,
		'uid' => $this->uid
		];  
        $model = new LotterysModel();
        // 查询奖品配置
        $prizeConfigSet = Lottery::getPrizeConfig($json['eid'],$json['prizeid']);
        if(!$prizeConfigSet){
            $this->echojson(['msg' => '', 'data' => []]);
        }
        // 中奖之后 选择自提/邮寄 ======== start
        if (isset($json['receive'])) {
            // 中奖之后填写地址时需要回传参数奖品ID, 根据奖品ID+eid+uid更新收货地址
            self::isRequired(array('prizeID', 'lotteryID'), true);
            // 查询抽奖记录
            $lotterys = $model->find("eid = :eid AND uid = :uid AND id=:id", array(':eid' => $this->eid, ':uid' => $this->uid, ':id' => $json['lotteryID']));
            if (empty($lotterys)) {
                $this->errmsg(I18NOld::translate('notWinRecord'));
            }
            // 奖品的信息
            $goods = Goods::model()->findByPk($json['prizeID']);
            // 自提/邮寄标识
            $lotterys->receive = $json['receive'];
            // 自提 记录姓名 电话 地址
            if ($json['receive'] == LotterysModel::RECEIVE_POST) {
                // 姓名、电话、收货地址 必传校验
                self::isRequired(array('username', 'tel', 'address'), true);
                $lotterys->username = $json['username'];
                $lotterys->tel = $json['tel'];
                $lotterys->address = $json['address'];
                $lotterys->goodsscore = $goods['score'];
            } else if ($json['receive'] == LotterysModel::RECEIVE_SELF) {
                $lotterys->goodsscore = $goods['score'];
                $lotterys->goodsaddress = $goods['address'];
//                $this->lottertGoods($json['eid'],$json['prizeid'],$json['prizeID'],$goods);
            } else {
                $this->errmsg(I18NOld::translate('parameterError'));
            }

            if(!$lotterys->save()){
                $this->errmsg(I18NOld::translate('operationFail'));
            }
            $this->echojson(['msg'=>'操作成功']);
            exit(0);
        }
        //判断后台是否开启了抽奖
        //时间放在后面 是为了解决,当用户抽到奖品了正在选择自提或者邮寄的时候,碰巧管理员关闭了抽奖,或者到了结束时间,就会出现提示:提交错误的问题
        // 中奖之后 选择自提/邮寄 ======== end
        //判断预设中奖人员 ======== start
        $preset = $this->presetInfoData($json);
        $dataRes = '';
        $prize = '';
        if(!empty($preset)){
            $sql = 'select * from yx_order where goods_id in ('.join(',',array_column($preset,'prize_id')).') AND uid = '.'"'.$json['userid'].'" AND prize_id = '.$json['prizeid'];
            $orderInfo = Yii::app()->db->createCommand($sql)->queryAll();
            //如果有 设置预设中奖人员,判断是否是第一次抽奖,是的话去第一个,不是的话,去掉之前抽过的,取差集,抽剩下的。
            if(empty($orderInfo)){
                $dataRes = array_rand(array_flip(array_column($preset,'prize_id')),1);
                $dataRes = $this->dataResQuery($dataRes);
            }else{
                $presetDiff = array_column($orderInfo,'goods_id');
                if(array_diff(array_column($preset,'prize_id'),$presetDiff)){
                    $dataRes = array_rand(array_flip(array_diff(array_column($preset,'prize_id'),$presetDiff)),1);
                }
                if(empty($dataRes)){
                    $prize = $this->getPrize($prizeConfigSet);
                }else{
                    $dataRes = $this->dataResQuery($dataRes);
                }
            }
            if(!empty($dataRes)){
                $dataRes['inside_person'] = '1';
            }
        }else{
            // 中奖奖品信息
            $prize = $this->getPrize($prizeConfigSet);
        }
        // 校验用户积分 是否充足
        if (!$this->checkUserScore($prizeConfigSet)) {
            $this->errmsg(I18NOld::translate('insufficientPoints'));
        }

        // 校验 时间是否正确
        $date = date("Y-m-d H:i:s");
        $start_time = '';
        $end_time = '';
        if (!empty($prizeConfigSet['start_time'])) {
            $start_time = date("Y-m-d H:i:s",$prizeConfigSet['start_time']);
        }
        if (!empty($prizeConfigSet['end_time'])) {
            $end_time = date("Y-m-d H:i:s",$prizeConfigSet['end_time']);
        }
        if(($start_time && $date < $start_time) || ($end_time && $date > $end_time)){
            $this->errmsg(I18NOld::translate('NotTimeLottery'));
        }

        // 查询抽奖记录获取最后一条记录的amount 查询抽奖次数
        $timesDay = $this->Datetime('d');
        $lotterys = $model->find("prize_id = :prize_id AND eid = :eid AND uid = :uid AND `time` > $timesDay[0] AND `time`< $timesDay[1] AND type =1 ORDER BY id DESC", [':prize_id'=>$json['prizeid'],':eid' => $this->eid, ':uid' => $this->uid]);

        $dbTransaction = Yii::app()->db->beginTransaction();
        try {
            if (!empty($lotterys)) {
                //设置抽奖次数,如果字段为0或者为空,视为无限制抽奖次数,次数为0,就可以一直抽奖,设置次数了会有抽奖上线
                if ($prizeConfigSet['frequency'] == 0 || $prizeConfigSet == "") {
                    $amount = 0;
                } else {
                    if ($lotterys->amount >= $prizeConfigSet['frequency']){
                        //$this->errmsg('抽奖次数已达上限');
                        $this->errmsg(I18NOld::translate('lottertTopLimit'));
                    }
                    $amount = $lotterys->amount + 1;
                }
            }
            $amount = !isset($amount)?1:$amount;
            $balanceTimes = $prizeConfigSet['frequency'] - $amount;
            $redeem = $this->redeem();
            $model->prize_id = $json['prizeid'];

            $prizeInfoId = empty($dataRes) ? $prize : $dataRes;

            $goods = Goods::model()->findByPk($prizeInfoId['id']);

            if ($prizeInfoId['id'] > 0) {
                // 更新库存前重新获取锁定后得库存, 防止并发扣减库存
                $prizeConfigSet = $this->getLockStock($model->prize_id);
                // 中奖奖品在奖品配置中 award 得索引值
                $awardIndex = array_search($prizeInfoId['id'],  array_column($prizeConfigSet['prize'], 'goodsid'));
                if ($prizeConfigSet['prize'][$awardIndex]['stock'] <= 0 || $goods['count'] <=0 ) {
                    //抽中了奖品,没有库存的时候,记录数据库时,兑换码redeem=""; $prize['stockLt']标识了是在这个状态下
                    $lotterysID = $model->addBaseData($json, $prizeInfoId, LotterysModel::STATUS_WAIT, $amount,'');
                    $prizeInfoId['stockLt'] = "0";
                }else{
                    $prizeInfoId['receive'] = $goods->receive;
                    $lotterysID = $model->addBaseData($json,$prizeInfoId, LotterysModel::STATUS_WAIT, $amount,$redeem);
                    $prizeInfoId['stockLt'] = "1";
                }
            }else{
                //真正的谢谢参与
                $lotterysID = $model->addBaseData($json, $prizeInfoId, LotterysModel::STATUS_WAIT, $amount,'');
            }

            if ($prizeInfoId['id'] > 0 && $prizeConfigSet['prize'][$awardIndex]['stock'] > 0 && $goods['count'] > 0) {
                // 更新库存
                $score = new Score($this->eid, $this->uid, 108);
                $score->add('draw',  I18NOld::translate('lotteryDeduction'), -$prizeConfigSet['consume_score'], $lotterysID);
                $msg = '恭喜中奖';
                $msg .= empty($prizeConfigSet['frequency']) ? "" :',剩余'.$balanceTimes.'次机会';
                $this->lottertGoods($json['eid'],$json['prizeid'],$goods->id,$goods);

            }else{
                // 未中奖或已无库存
                if(isset($prizeInfoId['stockLt'])){
                    //没有库存,不减少积分
                    $msg = I18NOld::translate('insufficientInventoryOfGoods');
                }else if($goods['count'] = 0 ){
                    $msg = I18NOld::translate('insufficientInventory');
                }else{
                    $score = new Score($this->eid, $this->uid, 108);
                    $score->add('draw',  I18NOld::translate('lotteryDeduction'), -$prizeConfigSet['consume_score'], $lotterysID);
                    // $msg = '很遗憾未中奖';
                    $msg = I18NOld::translate('unfortunately');
                }
                $msg .= empty($prizeConfigSet['frequency']) ? "" :($balanceTimes <= 0 ? ',机会已用完了' : ',还有'.$balanceTimes.'次机会');
            }
            $dbTransaction->commit();
            $prizeInfoId['lotteryId'] = $lotterysID;
            if ($lotteryData && $lotteryData->obj_type == Lottery::OBJ_TYPE_TRAIN) {//关联培训计划,更新培训计划完成状态
                (new TrainState($this->eid, $lotteryData->obj_id, $this->uid))->update('lottery', $lotteryData->id, 1);
            }
            $this->echojson(['msg' => $msg, 'data' => $prizeInfoId]);
        }catch (Exception $e){
            $dbTransaction->rollback();
            var_dump('lottery:'.json_encode($e, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));die();
            $this->errmsg(!empty($e->getMessage()) ? $e->getMessage() : I18NOld::translate('luckDrawFail'));
        }
    }

封装的 所有类

    /**
     * Application getPrize 使用 FOR UPDATE 锁定库存
     * Author FYC
     * @Created on 2021/04/29 10:25
     */
    private function getLockStock($prizeid)
    {
        $prizeConfigSetSQL = 'SELECT award_name,frequency,consume_score,prize,`explain`,start_time,end_time,luck_draw_num,luckDrawProbability,switch FROM {{prize_configure}} WHERE id = '.$prizeid.' FOR UPDATE';
        $prizeConfigSetRes = Yii::app()->db->createCommand($prizeConfigSetSQL)->queryRow();
        // 奖品配置错误
        if(empty($prizeConfigSetRes) ||!isset($prizeConfigSetRes['prize']) || empty($prizeConfigSetRes['prize']) ){
            //$this->errmsg('异常错误, 请稍后再试');
            $this->errmsg(I18NOld::translate('exceptionError'));
        }
        $prizeConfigSetRes['prize'] =  json_decode($prizeConfigSetRes['prize'], true);
        return $prizeConfigSetRes;
    }
    /**
     * Application getPrize 获取中奖奖品信息
     * Author FYC
     * @param array $prizeConfigSet 奖品配置
     * @Created on 2021/04/29 10:35
     */
    private function getPrize($prizeConfigSet)
    {
        if(!$prizeConfigSet) $this->errmsg(I18NOld::translate('parameterError'));
        $prize        = []; // 中奖奖品信息
        $probConfig   = []; // 概率配置
        $allPrizeInfo = []; // 所有奖品信息(id img name)
        foreach ($prizeConfigSet['prize'] as $val)
        {
            $goods = Goods::model()->findByPk($val['goodsid']);
            $probConfig[$val['goodsid']] = $val['prob'];
            $arr = explode(',',$goods['img']);
            $current  =  current($arr);
            // 所有奖品信息(id img name)
            $allPrizeInfo[$val['goodsid']]['img']  = $current;
            $allPrizeInfo[$val['goodsid']]['name'] = $goods['name'];
            $allPrizeInfo[$val['goodsid']]['address'] = isset($goods->address) ? $goods->address : '';
        }
        // 根据概率获取奖项id
        $prize['id']   = $this->getRand($probConfig);
        // 获取中奖奖品图片和名称
        $prize['img']  = $this->attachmentUrl($allPrizeInfo[$prize['id']]['img']); // 这个方法里面需要判断传入得字符串是否为空
        $prize['name'] = empty($allPrizeInfo[$prize['id']]['name'])?"谢谢参与":$allPrizeInfo[$prize['id']]['name'];
        $prize['address'] = $allPrizeInfo[$prize['id']]['address'];
        return $prize;
    }
    public function getRand($record) {
        $data = '';
        $proSum = array_sum($record); //概率数组的总概率精度
        foreach ($record as $k => $v) { //概率数组循环
            $randNum = mt_rand(1, $proSum);
            if ($randNum <= $v) {
                $data = $k;
                break;
            } else {
                $proSum -= $v;
            }
        }
        unset($proArr);
        return $data;
    }
    /**
     * Application checkUserScore 校验用户积分
     * Author C
     * @param array $prizeConfigSet 奖品配置 
     */
    private function checkUserScore($prizeConfigSet)
    {
        // 查询用户积分
        $userScore = Userinfo::model()->find([
            'select'    => 'score',
            'condition' => 'eid = :eid AND uid = :uid',
            'params'    => [':eid' => $this->eid, ':uid' => $this->uid]
        ]);
        return !empty($userScore) && $userScore->score >= $prizeConfigSet['consume_score'];
    }

    //兑换码
    public function redeem($length = 6, $type = "ALL")
    {
        switch ($type) {
            case "ALL":
                $chars = 'ZXCVBNMLKJHGFDSAQWERTYUIOPpoiuytrewqasdfghjklmnbvcxz1234567890';
                break;
            case "STRING":
                $chars = 'qwertyuioplkjhgfdsazxcvbnmMNBVCXZASDFGHJKLPOIUYTREWQ';
                break;
            case "NUMBER":
                $chars = '1234567890';
                break;
        }
        mt_srand((double)microtime() * 1000000 * getmypid());
        $rows = '';
        while (strlen($rows) < $length) {
            $rows .= substr($chars, (mt_rand() % strlen($chars)), 1);
        }
        return $rows;
    }
    /**
     * AppLication: lottertGoods 抽奖扣除库存的方法调用
     * Author: C
     * @param $eid
     * @param $prizeid
     * @param $prizeID
     * @param $goods
     * @throws ErrorException 
     */
    public function lottertGoods($eid,$prizeid,$prizeID,$goods){
        $res = Lottery::updateStock($eid,$prizeid,$prizeID);
        (new Lottery())->getRedisKetValue($res,$eid,empty($_GET['id'])?'':$_GET['id']);
        $goods['count'] -= 1; // 减库存
        Lottery::updateGoods($eid, $goods);
    }

    public function dataResQuery($id){
        $goods = Goods::model()->findByPk($id);
        $presetData['id'] = $goods->id;
        $presetData['name'] = $goods->name;
        $presetData['img']  = $this->attachmentUrl($goods->img);
        $presetData['address'] = $goods->address;
        return $presetData;
    }
    public function presetInfoData($json){
        $sql = 'select prize_id from yx_preset_prizes where  p_id = '.$json['prizeid'].' AND uid = '.'"'.$json['userid'].'"';
        return Yii::app()->db->createCommand($sql)->queryAll();
    }
}

/**
     * Application getPrizeConfig 获取中奖奖品信息
     * Author C
     * @param int $eid 企业ID
     * @param $prizeid 奖品id
     * @return array 
     */
    public static function getPrizeConfig($eid,$prizeid)
    {
        // 查询奖品配置
        $redisCache = Yii::app()->redisCache;
        $prizeConfigSet = $redisCache->hgetall((new Lottery)->getRedisKey($eid,$prizeid),$prizeid);
        if(!$prizeConfigSet){
            $sql = 'select award_name,frequency,consume_score,prize,`explain`,start_time,end_time,luck_draw_num,luckDrawProbability,switch from {{prize_configure}}  where id ='.$prizeid .' AND eid = '.$eid;
            $prizeConfigSet = Yii::app()->db->createCommand($sql)->queryRow();
        }
        if($prizeConfigSet){
            $prizeConfigSet['prize'] =   @json_decode($prizeConfigSet['prize'], true);
            $thankNum = [];
            foreach($prizeConfigSet['prize'] as $key => $val){
                $prizeProb[$key] = $val['prob'];
            }
            $thanks = self::$noPrize;
            $thanks[0]['prob'] = (100-array_sum($prizeProb))/2;
            $thanks[1]['prob'] = (100-array_sum($prizeProb))/2;
            $prizeConfigSet['prize'] = array_merge($prizeConfigSet['prize'],$thanks );
            return $prizeConfigSet;
        }else{
           return false;
        }
    }

/**
     * Application getPrizeConfig 获取中奖奖品信息
     * Author C
     * @param array $json 用户数据
     * @param array $prize 奖品数据
     * @param int $status 兑换状态
     * @param int $amount 抽奖次数
     * @param string $redeem 兑换码
     * @return int 
     * @throws ErrorException
     */
    public function addBaseData($json, $prize, $status, $amount, $redeem)
    {
        $this->eid       = $json['eid'];
        $this->uid       = $json['userid'];
        $this->goods_id  = $prize['id'];
        $this->goodsimg  = ltrim(parse_url($prize['img'],PHP_URL_PATH),'/');
        $this->goodsname = empty($redeem) ? '谢谢参与': $prize['name'];
        $this->type      = self::TYPE_LOTTERY;
        $this->status    = $status;
        $this->amount    = $amount;
        $this->redtime    = time();
        $this->time    = time();
        $this->inside_person    = empty($prize['inside_person'])?'':$prize['inside_person'];
        if ($prize['name'] != '谢谢参与') {
            $this->redeem = $redeem;
        } 
        if (!$this->save())
 			throw new ErrorException('抽奖失败, 请刷新重试');
        return $this->id;
    }

PHP YII 抽奖接口,大转盘抽奖 抽奖代码 【附源码+完整版】_第2张图片

你可能感兴趣的:(PHP学习记录,php,数据库,json)