/**
* 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);
}
抽奖 开始代码
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;
}