This commit is contained in:
2026-01-27 19:25:16 +08:00
parent 5f5954da52
commit 935ef9f998
6 changed files with 731 additions and 24 deletions

View File

@@ -83,7 +83,18 @@ class Lottery extends adminApi
$page_limit = input('page_limit', 30);
$stime = input('stime', '');
$etime = input('etime', '');
$pool_type = input('pool_type', '1');
$user_code = input('user_code');
if($user_code){
$userId = db::name('user')->where(['user_code'=>$user_code])->value('id');
if($userId){
$where['uid'] = $userId;
}else{
$where['uid'] = '1';
}
}
$where = [];
$where['prize_type'] = $pool_type;
if($stime!==""){
$where['create_time'] = ['>=', strtotime($stime)];
}
@@ -94,7 +105,9 @@ class Lottery extends adminApi
$where['create_time'] = ['between', [strtotime($stime), strtotime($etime)]];
}
$count = db::name('bb_lottery_winner_record')->where($where)->count();
$lists_data = db::name('bb_lottery_winner_record')->field('id,uid as user_id,prize_type,prize_amount,pool_amount,ratio,release_amount,status,create_time as createtime')->where($where)->page($page, $page_limit)->order("id desc")->select();
$lists_data = db::name('bb_lottery_winner_record')
->field('id,uid as user_id,prize_type,prize_amount,pool_amount,ratio,release_amount,status,create_time as createtime')
->where($where)->page($page, $page_limit)->order("id desc")->select();
foreach ($lists_data as $k=>$v){
if($v['user_id'] > 0){
$user_info = db::name('user')->where(['id'=>$v['user_id']])->find();
@@ -106,7 +119,16 @@ class Lottery extends adminApi
}
//奖项类型1-小奖 2-大奖
$lists_data[$k]['prize_type_str'] = $v['prize_type']==1?"小奖":"大奖";
if($v['prize_type']==4){
$lists_data[$k]['prize_type_str'] = "高级奖";
}elseif ($v['prize_type']==2){
$lists_data[$k]['prize_type_str'] = "大奖";
}elseif ($v['prize_type']==3){
$lists_data[$k]['prize_type_str'] = "中级奖";
}else{
$lists_data[$k]['prize_type_str'] = "小奖";
}
//状态1-已发放 0-未发放'
$lists_data[$k]['status_str'] = $v['status']==1?"已发放":"未发放";
$lists_data[$k]['createtime'] = date("Y-m-d H:i:s", $v['createtime']);
@@ -128,23 +150,48 @@ class Lottery extends adminApi
* 实时统计
*/
public function realtime_statistics(){
$pool_type = input('pool_type', '1');
$bb_config = db::name('bb_lottery_config')->field('key,value')->select();
$bb_config = array_column($bb_config, null, 'key');
// 循环奖池进度
//最新轮次
$latest_times = db::name('bb_lottery_pool_flow')->where(['pool_type'=>1])->max('times');
$pool_progress = db::name('bb_lottery_pool_flow')->where(['pool_type'=>1,'times'=>$latest_times])->count();//当前进度
$pool_total_amount = db::name('bb_lottery_pool_flow')->where(['pool_type'=>1,'times'=>$latest_times,'type'=>1])->sum('amount');
//获取配置表中奖池配置
$pool_progress_str = $pool_progress."/".$bb_config['small_pool_trigger_times']['value']."(".$pool_total_amount."金币)";
if($pool_type == 4){
$latest_times = db::name('bb_lottery_pool_flow_10')->where(['pool_type'=>1])->max('times');//最新轮次
$pool_progress = db::name('bb_lottery_pool_flow_10')->where(['pool_type'=>1,'times'=>$latest_times])->count();//当前进度
$pool_total_amount = db::name('bb_lottery_pool_flow_10')->where(['pool_type'=>1,'times'=>$latest_times,'type'=>1])->sum('amount');
//获取配置表中奖池配置
$pool_progress_str = $pool_progress."/".$bb_config['small_pool_trigger_times_10']['value']."(".$pool_total_amount."金币)";
//最近中奖用户
$last_winner_user_id = db::name('bb_lottery_winner_record')->where(['status'=>1,'prize_type'=>4])->order('id desc')->find();
//平台累计收入
$platform_total_income = db::name('bb_lottery_winner_record')->where(['prize_type'=>4])->sum('release_amount');
}elseif($pool_type == 3){
$latest_times = db::name('bb_lottery_pool_flow_5')->where(['pool_type'=>1])->max('times');//最新轮次
$pool_progress = db::name('bb_lottery_pool_flow_5')->where(['pool_type'=>1,'times'=>$latest_times])->count();//当前进度
$pool_total_amount = db::name('bb_lottery_pool_flow_5')->where(['pool_type'=>1,'times'=>$latest_times,'type'=>1])->sum('amount');
//获取配置表中奖池配置
$pool_progress_str = $pool_progress."/".$bb_config['small_pool_trigger_times_5']['value']."(".$pool_total_amount."金币)";
//最近中奖用户
$last_winner_user_id = db::name('bb_lottery_winner_record')->where(['status'=>1,'prize_type'=>3])->order('id desc')->find();
//平台累计收入
$platform_total_income = db::name('bb_lottery_winner_record')->where(['prize_type'=>3])->sum('release_amount');
}else{
$latest_times = db::name('bb_lottery_pool_flow')->where(['pool_type'=>1])->max('times');//最新轮次
$pool_progress = db::name('bb_lottery_pool_flow')->where(['pool_type'=>1,'times'=>$latest_times])->count();//当前进度
$pool_total_amount = db::name('bb_lottery_pool_flow')->where(['pool_type'=>1,'times'=>$latest_times,'type'=>1])->sum('amount');
//获取配置表中奖池配置
$pool_progress_str = $pool_progress."/".$bb_config['small_pool_trigger_times']['value']."(".$pool_total_amount."金币)";
//最近中奖用户
$last_winner_user_id = db::name('bb_lottery_winner_record')->where(['status'=>1,'prize_type'=>1])->order('id desc')->find();
//平台累计收入
$platform_total_income = db::name('bb_lottery_winner_record')->where(['prize_type'=>1])->sum('release_amount');
}
//蓄水池当前金额
$big_round = db::name('bb_lottery_pool_flow')->where(['pool_type'=>2])->max('times');
$bigAddGold = Db::name('bb_lottery_pool_flow')
->where(['pool_type' => 2, 'type' => 3, 'times' => $big_round])
->sum('amount') ?: 0;
//最近中奖用户
$last_winner_user_id = db::name('bb_lottery_winner_record')->where(['status'=>1])->order('id desc')->find();
// $big_round = db::name('bb_lottery_pool_flow')->where(['pool_type'=>2])->max('times');
// $bigAddGold = Db::name('bb_lottery_pool_flow')->where(['pool_type' => 2, 'type' => 3, 'times' => $big_round])->sum('amount') ?: 0;
$bigAddGold = 0;
if($last_winner_user_id){
$last_winner_user_info = db::name('user')->where(['id'=>$last_winner_user_id['uid']])->find();
$last_winner_user_text = "用户ID:".$last_winner_user_info['user_code']." 获得 ".$last_winner_user_id['prize_amount']." 金币 ".$last_winner_user_id['ratio']."%)";
@@ -154,7 +201,7 @@ class Lottery extends adminApi
//平台累计收入
// $platform_total_income = db::name('bb_lottery_pool_flow')->where(['type'=>4])->sum('amount');
$platform_total_income = db::name('bb_lottery_winner_record')->where(['prize_type'=>1])->sum('release_amount');
$return_data=[
'pool_progress' => $pool_progress_str,
'pool_amount_now' => ($bigAddGold)."金币 ".(($bigAddGold)/$bb_config['big_pool_threshold']['value'])."%)",

View File

@@ -31,9 +31,12 @@ class SendGift extends BaseCom
}
//获取幸运币
$pool_gift_id = db::name('bb_lottery_config')->where(['key' => 'pool_gift_id'])->value('value');
if($gift_id == $pool_gift_id){//送的是幸运币
$reslut = model('Lottery')->gift($this->uid, $to_uid, $gift_id, $room_id,$gift_num);
$pool_gift_ids = Db::name('bb_lottery_config')->column('value', 'key');
//转成数组
$pool_gift_id_arr = [$pool_gift_ids['pool_gift_id']??0,$pool_gift_ids['pool_gift_id_5']??0,$pool_gift_ids['pool_gift_id_10']??0];
if(in_array($gift_id, $pool_gift_id_arr)){//送的是幸运币
$reslut = model('Lottery')->gift($this->uid, $to_uid, $gift_id, $room_id,$gift_num,$pool_gift_ids);
redis_unlocks($key_name);
return V($reslut['code'], $reslut['msg'], $reslut['data']);
}else{

View File

@@ -4,6 +4,8 @@ namespace app\api\model;
use app\common\controller\Push;
use app\common\service\LotteryService;
use app\common\service\LotteryService5;
use app\common\service\LotteryService10;
use think\Db;
use think\Exception;
use think\Log;
@@ -15,7 +17,7 @@ class Lottery extends Model
* 送礼参与抽奖接口
* @return json
*/
public function gift($send_uid, $recv_uid,$gift_id, $room_id, $num)
public function gift($send_uid, $recv_uid, $gift_id, $room_id, $num, $pool_gift_ids)
{
if (ceil($num) != $num) {
return ['code' => 0, 'msg' => '打赏礼物数量必须为整数', 'data' => null];
@@ -65,6 +67,18 @@ class Lottery extends Model
$lucky_rate = db::name('bb_lottery_config')->where(['key' => 'lucky_rate'])->value('value');
$recv_coin = round($gift_price * $lucky_rate / 100, 2);
$small_pool = $gift_price - $recv_coin;
if($gift_id == $pool_gift_ids['pool_gift_id_5']){
$table = 'bb_lottery_gift_record_5';
$poole_type = 5;
}elseif ($gift_id == $pool_gift_ids['pool_gift_id_10']){
$table = 'bb_lottery_gift_record_10';
$poole_type = 10;
}else{
$table = 'bb_lottery_gift_record';
$poole_type = 1;
}
foreach ($toarray as $k => $to_id){
// 1. 记录礼物赠送
$giftRecord = [
@@ -77,7 +91,7 @@ class Lottery extends Model
'create_time' => time(),
'remark' => '幸运币收益率'.$lucky_rate.'%'
];
$giftId = Db::name('bb_lottery_gift_record')->insertGetId($giftRecord);
$giftId = Db::name($table)->insertGetId($giftRecord);
//收礼记录行为日志
$give_gift = model('api/SendGift')->change_user_give_gift_logs($send_uid,$gift_id,$gift_price,$num,$to_id,2,1,0,'送幸运币');
@@ -121,7 +135,7 @@ class Lottery extends Model
//计算爆币
$nums = $num * count($toarray);
$ress = $this->lottery($send_uid,$gift_info['gift_price'],$nums,$room_id,$gift_id,$FromUserInfo,$gift_info);
$ress = $this->lottery($send_uid,$gift_info['gift_price'],$nums,$room_id,$gift_id,$FromUserInfo,$gift_info,$poole_type);
if($ress['code'] == 0){
return ['code' => 0, 'msg' => $ress['msg'], 'data' => null];
}
@@ -131,12 +145,19 @@ class Lottery extends Model
//抽奖(不带大奖池)
public function lottery($send_uid,$gift_price,$num,$room_id,$giftId,$fromUserInfo=null,$gift_info=null)
public function lottery($send_uid,$gift_price,$num,$room_id,$giftId,$fromUserInfo=null,$gift_info=null,$poole_type = 1)
{
$small_prize_play_image = db::name('bb_lottery_config')->where(['key' => 'small_prize_play_image'])->value('value');
try {
$gift_gold = $gift_price;
$service = new LotteryService();
if($poole_type == 5){
$service = new LotteryService5();
}elseif ($poole_type == 10){
$service = new LotteryService10();
}else{
$service = new LotteryService();
}
for($i=0;$i<$num;$i++){
$reslut = $service->handleGift($send_uid, $gift_gold, $giftId);
if ($reslut['code'] == 1) {

View File

@@ -65,6 +65,137 @@ if small_total_times >= small_trigger_times then
result.small_round = small_round
end
-- 返回结果
return cjson.encode(result)
LUA;
}
// 获取Lua脚本
public static function getLotteryLuaScript5()
{
return <<<LUA
-- 接收参数send_uid, gift_gold, small_trigger_times, big_threshold, small_round, big_round, big_total_gold
local send_uid = ARGV[1]
local gift_gold = tonumber(ARGV[2])
local small_trigger_times = tonumber(ARGV[3]) or 200 -- 小奖池触发次数
local small_round = tonumber(ARGV[4]) -- 小奖池当前轮次
local lucky_rate = tonumber(ARGV[5]) -- 收益率
local lottery_rate = tonumber(ARGV[6]) -- 爆币率
-- 1. 基础金额拆分
local pool_add_rate = 100 - lucky_rate -- 累加金币率
local small_pool_add = gift_gold * pool_add_rate / 100 -- 累加金币
-- 2. Redis键定义
local small_round_key = "lottery:small_pool:round_5"
local small_total_times_key = "lottery:small_pool:total_times_5"
local small_total_gold_key = "lottery:small_pool:total_gold_5"
-- 初始化轮次确保Redis与入参一致
redis.call('set', small_round_key, small_round)
-- 3. 小奖池累计更新
local small_total_times = tonumber(redis.call('incr', small_total_times_key))
local small_total_gold = tonumber(redis.call('get', small_total_gold_key) or 0)
small_total_gold = small_total_gold + small_pool_add
redis.call('set', small_total_gold_key, small_total_gold)
-- 4. 返回结果初始化(区分大小轮次)
local result = {
send_uid = send_uid,
gift_gold = gift_gold,
small_pool_add = small_pool_add,
small_total_times = small_total_times,
small_total_gold = small_total_gold,
is_small_prize = 0,
small_prize_amount = 0,
small_round = small_round, -- 小奖池轮次
}
-- 5. 小奖池开奖判断(小轮次+1
if small_total_times >= small_trigger_times then
result.is_small_prize = 1
-- 小奖随机比例
local small_ratio = math.random(2, lottery_rate)
result.small_prize_amount = math.floor(small_total_gold * small_ratio / 100 * 100) / 100
-- 重置小奖池,小轮次+1
redis.call('set', small_total_times_key, 0)
redis.call('set', small_total_gold_key, 0)
small_round = small_round + 1
redis.call('set', small_round_key, small_round)
result.small_round = small_round
end
-- 返回结果
return cjson.encode(result)
LUA;
}
// 获取Lua脚本
public static function getLotteryLuaScript10()
{
return <<<LUA
-- 接收参数send_uid, gift_gold, small_trigger_times, big_threshold, small_round, big_round, big_total_gold
local send_uid = ARGV[1]
local gift_gold = tonumber(ARGV[2])
local small_trigger_times = tonumber(ARGV[3]) or 200 -- 小奖池触发次数
local small_round = tonumber(ARGV[4]) -- 小奖池当前轮次
local lucky_rate = tonumber(ARGV[5]) -- 收益率
local lottery_rate = tonumber(ARGV[6]) -- 爆币率
-- 1. 基础金额拆分
local pool_add_rate = 100 - lucky_rate
local small_pool_add = gift_gold * pool_add_rate / 100
-- 2. Redis键定义
local small_round_key = "lottery:small_pool:round_10"
local small_total_times_key = "lottery:small_pool:total_times_10"
local small_total_gold_key = "lottery:small_pool:total_gold_10"
-- 初始化轮次确保Redis与入参一致
redis.call('set', small_round_key, small_round)
-- 3. 小奖池累计更新
local small_total_times = tonumber(redis.call('incr', small_total_times_key))
local small_total_gold = tonumber(redis.call('get', small_total_gold_key) or 0)
small_total_gold = small_total_gold + small_pool_add
redis.call('set', small_total_gold_key, small_total_gold)
-- 4. 返回结果初始化(区分大小轮次)
local result = {
send_uid = send_uid,
gift_gold = gift_gold,
small_pool_add = small_pool_add,
small_total_times = small_total_times,
small_total_gold = small_total_gold,
is_small_prize = 0,
small_prize_amount = 0,
small_round = small_round, -- 小奖池轮次
}
-- 5. 小奖池开奖判断(小轮次+1
if small_total_times >= small_trigger_times then
result.is_small_prize = 1
-- 小奖随机比例
local small_ratio = math.random(2, lottery_rate)
result.small_prize_amount = math.floor(small_total_gold * small_ratio / 100 * 100) / 100
-- 重置小奖池,小轮次+1
redis.call('set', small_total_times_key, 0)
redis.call('set', small_total_gold_key, 0)
small_round = small_round + 1
redis.call('set', small_round_key, small_round)
result.small_round = small_round
end
-- 返回结果
return cjson.encode(result)
LUA;

View File

@@ -0,0 +1,252 @@
<?php
namespace app\common\service;
use app\common\library\LotteryGiftLua;
use think\Cache;
use think\Db;
use think\Exception;
class LotteryService10
{
// Redis实例
private $redis;
// 配置参数
private $config;
private $bigPrizeWeights;
public function __construct()
{
$this->redis = Cache::store('redis')->handler();
// 加载配置
$this->config = Db::name('bb_lottery_config')->column('value', 'key');
// 初始化Redis缓存若Redis数据丢失从数据库恢复
$this->initRedisFromDb();
}
/**
* 缓存恢复:独立恢复大小轮次+对应金额
*/
private function initRedisFromDb()
{
// 1. 恢复小奖池轮次取pool_type=1的最大times
$maxSmallRound = Db::name('bb_lottery_pool_flow_10')->where('pool_type', 1)->max('times') ?: 1;
if (!$this->redis->get('lottery:small_pool:round_10')) {
$this->redis->set('lottery:small_pool:round_10', $maxSmallRound);
}
// 2. 恢复小奖池当前轮次的次数/金额
$small_round = intval($this->redis->get('lottery:small_pool:round_10'));
if (!$this->redis->get('lottery:small_pool:total_times_10')) {
$smallTotalTimes = Db::name('bb_lottery_pool_flow_10')
->where(['pool_type' => 1, 'type' => 1, 'times' => $small_round])
->count();
$this->redis->set('lottery:small_pool:total_times_10', $smallTotalTimes);
}
if (!$this->redis->get('lottery:small_pool:total_gold_10')) {
$smallTotalGold = Db::name('bb_lottery_pool_flow_10')
->where(['pool_type' => 1, 'type' => 1, 'times' => $small_round])
->sum('amount') ?: 0;
$this->redis->set('lottery:small_pool:total_gold_10', $smallTotalGold);
}
}
/**
* 处理送礼抽奖逻辑
* @param int $send_uid 送礼用户ID
* @param float $gift_gold 礼物金币数
* @param int $giftId 礼物ID
* @return array 处理结果
* @throws Exception
*/
public function handleGift($send_uid, $gift_gold, $giftId)
{
// 参数校验
if ($gift_gold <= 0 || !$send_uid) {
throw new Exception('参数错误');
}
// 读取配置+独立轮次
$small_trigger_times = intval($this->config['small_pool_trigger_times_10'] ?? 200);//触发抽奖次数
$small_round = intval($this->redis->get('lottery:small_pool:round_10') ?: 1);//小奖轮次
$lucky_rate = intval($this->config['lucky_rate'] ?? 1);//收益率
$lottery_rate = intval($this->config['lottery_rate_10'] ?? 100);//爆币率
if($lottery_rate <= 2){
throw new Exception('配置错误');
}
// 加载Lua脚本
$luaSha = LotteryGiftLua::getLotteryLuaScript();
// 执行Lua脚本入参small_round + big_round
$result = $this->redis->eval($luaSha, [
$send_uid,
$gift_gold,
$small_trigger_times,
$small_round,
$lucky_rate,
$lottery_rate
], 0);
$result = json_decode($result, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception('Lua脚本执行失败');
}
// 开启数据库事务
Db::startTrans();
try {
// . 1记录小奖池累计流水未开奖时
if ($result['is_small_prize'] == 0) {
$this->addPoolFlow(
1, // 小奖池
1, // 累计
$result['small_pool_add'],
$result['small_total_gold'] - $result['small_pool_add'],
$result['small_total_gold'],
$giftId,
$result['small_round'], // 新增:传入轮次
"小奖池累计:用户{$send_uid}送礼,轮次{$result['small_round']}"
);
} else {
$winnerUid = $send_uid; // 奖默认给当前送礼用户
// 小奖中奖记录
$this->addWinnerRecord(
$winnerUid,
4, // 高级奖池
$result['small_prize_amount'],//中奖金额
$result['small_total_gold'],//奖池总金额
$this->getSmallRatio($result['small_prize_amount'], $result['small_total_gold']),//中奖比例
$result['small_total_gold'] - floor($result['small_prize_amount']) //释放金额
);
// 3. 小奖池开奖流水
$this->addPoolFlow(
1, //
2, //
$result['small_prize_amount'],
$result['small_total_gold'],
$result['small_total_gold'] - $result['small_prize_amount'],
$giftId,
$result['small_round'] - 1, // 开奖轮次为当前轮次-1已结束的轮次
"小奖池开奖:轮次" . ($result['small_round'] - 1).",中奖金额:{$result['small_prize_amount']}金币"
);
}
Db::commit();
return [
'code' => 1,
'msg' => '处理成功',
'data' => $result
];
} catch (Exception $e) {
Db::rollback();
throw new Exception($e->getMessage());
}
}
/**
* 添加奖池流水
* @param int $pool_type 奖池类型1-小 2-大
* @param int $type 流水类型1-累计 2-开奖 3-划转 4-释放
* @param float $amount 金额
* @param float $before_amount 操作前金额
* @param float $after_amount 操作后金额
* @param int $relate_id 关联ID
* @param int $times 轮次
* @param string $remark 备注
*/
private function addPoolFlow($pool_type, $type, $amount, $before_amount, $after_amount, $relate_id, $times, $remark)
{
Db::name('bb_lottery_pool_flow_10')->insert([
'pool_type' => $pool_type,
'type' => $type,
'amount' => $amount,
'before_amount' => $before_amount,
'after_amount' => $after_amount,
'relate_id' => $relate_id,
'times' => $times, // 新增:写入轮次
'remark' => $remark,
'create_time' => time()
]);
}
/**
* 添加中奖记录
* @param int $uid 中奖用户ID
* @param int $prize_type 奖项类型1-小 2-大
* @param float $prize_amount 中奖金额
* @param float $pool_amount 奖池总金额
* @param int $ratio 中奖比例
* @param float $release_amount 释放金额
*/
private function addWinnerRecord($uid, $prize_type, $prize_amount, $pool_amount, $ratio, $release_amount)
{
Db::name('bb_lottery_winner_record')->insert([
'uid' => $uid,
'prize_type' => $prize_type,
'prize_amount' => $prize_amount,
'pool_amount' => $pool_amount,
'ratio' => $ratio,
'release_amount' => $release_amount,
'create_time' => time(),
'status' => 1 // 已发放
]);
// 此处可添加用户金币入账逻辑(如更新用户金币表)
}
/**
* 计算小奖中奖比例
* @param float $prize_amount 中奖金额
* @param float $pool_amount 奖池金额
* @return int 比例(%
*/
private function getSmallRatio($prize_amount, $pool_amount)
{
return intval(round($prize_amount / $pool_amount * 100));
}
/**
* 计算大奖中奖比例
* @param float $prize_amount 中奖金额
* @param float $pool_amount 奖池金额
* @return int 比例(%
*/
private function getBigRatio($prize_amount, $pool_amount)
{
return intval(round($prize_amount / $pool_amount * 100));
}
/**
* 统计中奖数据
* @param array $where 筛选条件如uid、prize_type、time
* @return array 统计结果
*/
public function statWinner($where = [])
{
$query = Db::name('bb_lottery_winner_record');
if (!empty($where['uid'])) {
$query->where('uid', $where['uid']);
}
if (!empty($where['prize_type'])) {
$query->where('prize_type', $where['prize_type']);
}
if (!empty($where['start_time']) && !empty($where['end_time'])) {
$query->whereBetween('create_time', [$where['start_time'], $where['end_time']]);
}
// 总中奖金额、总释放金额、中奖次数
$stat = $query->field([
'SUM(prize_amount) as total_prize',
'SUM(release_amount) as total_release',
'COUNT(id) as total_times'
])->find();
return [
'total_prize' => $stat['total_prize'] ?? 0,
'total_release' => $stat['total_release'] ?? 0,
'total_times' => $stat['total_times'] ?? 0
];
}
}

View File

@@ -0,0 +1,253 @@
<?php
namespace app\common\service;
use app\common\library\LotteryGiftLua;
use think\Cache;
use think\Db;
use think\Exception;
class LotteryService5
{
// Redis实例
private $redis;
// 配置参数
private $config;
private $bigPrizeWeights;
public function __construct()
{
$this->redis = Cache::store('redis')->handler();
// 加载配置
$this->config = Db::name('bb_lottery_config')->column('value', 'key');
// 初始化Redis缓存若Redis数据丢失从数据库恢复
$this->initRedisFromDb();
}
/**
* 缓存恢复:独立恢复大小轮次+对应金额
*/
private function initRedisFromDb()
{
// 1. 恢复奖池轮次取pool_type=1的最大times
$maxSmallRound = Db::name('bb_lottery_pool_flow_5')->where('pool_type', 1)->max('times') ?: 1;
if (!$this->redis->get('lottery:small_pool:round_5')) {
$this->redis->set('lottery:small_pool:round_5', $maxSmallRound);
}
// 2. 恢复奖池当前轮次的次数/金额
$small_round = intval($this->redis->get('lottery:small_pool:round_5'));
if (!$this->redis->get('lottery:small_pool:total_times_5')) {
$smallTotalTimes = Db::name('bb_lottery_pool_flow_5')
->where(['pool_type' => 1, 'type' => 1, 'times' => $small_round])
->count();
$this->redis->set('lottery:small_pool:total_times_5', $smallTotalTimes);
}
if (!$this->redis->get('lottery:small_pool:total_gold_5')) {
$smallTotalGold = Db::name('bb_lottery_pool_flow_5')
->where(['pool_type' => 1, 'type' => 1, 'times' => $small_round])
->sum('amount') ?: 0;
$this->redis->set('lottery:small_pool:total_gold_5', $smallTotalGold);
}
}
/**
* 处理送礼抽奖逻辑
* @param int $send_uid 送礼用户ID
* @param float $gift_gold 礼物金币数
* @param int $giftId 礼物ID
* @return array 处理结果
* @throws Exception
*/
public function handleGift($send_uid, $gift_gold, $giftId)
{
// 参数校验
if ($gift_gold <= 0 || !$send_uid) {
throw new Exception('参数错误');
}
// 读取配置+独立轮次
$small_trigger_times = intval($this->config['small_pool_trigger_times_5'] ?? 200);//触发抽奖次数
$small_round = intval($this->redis->get('lottery:small_pool:round_5') ?: 1);//轮次
$lucky_rate = intval($this->config['lucky_rate'] ?? 1);//收益率
$lottery_rate = intval($this->config['lottery_rate_5'] ?? 100);//爆币率
if($lottery_rate <= 2){
throw new Exception('配置错误');
}
// 加载Lua脚本
$luaSha = LotteryGiftLua::getLotteryLuaScript5();
// 执行Lua脚本入参small_round + big_round
$result = $this->redis->eval($luaSha, [
$send_uid,
$gift_gold,
$small_trigger_times,
$small_round,
$lucky_rate,
$lottery_rate
], 0);
$result = json_decode($result, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception('Lua脚本执行失败');
}
// 开启数据库事务
Db::startTrans();
try {
// . 1记录小奖池累计流水未开奖时
if ($result['is_small_prize'] == 0) {
$this->addPoolFlow(
1, // 中级奖池
1, // 累计
$result['small_pool_add'],
$result['small_total_gold'] - $result['small_pool_add'],
$result['small_total_gold'],
$giftId,
$result['small_round'], // 新增:传入轮次
"小奖池累计:用户{$send_uid}送礼,轮次{$result['small_round']}"
);
} else {
$winnerUid = $send_uid; // 奖默认给当前送礼用户
// 小奖中奖记录
$this->addWinnerRecord(
$winnerUid,
3, // 中级奖
$result['small_prize_amount'],//中奖金额
$result['small_total_gold'],//奖池总金额
$this->getSmallRatio($result['small_prize_amount'], $result['small_total_gold']),//中奖比例
$result['small_total_gold'] - floor($result['small_prize_amount']) //释放金额
);
// 3. 小奖池开奖流水
$this->addPoolFlow(
1, //
2, //
$result['small_prize_amount'],
$result['small_total_gold'],
$result['small_total_gold'] - $result['small_prize_amount'],
$giftId,
$result['small_round'] - 1, // 开奖轮次为当前轮次-1已结束的轮次
"小奖池开奖:轮次" . ($result['small_round'] - 1).",中奖金额:{$result['small_prize_amount']}金币"
);
}
Db::commit();
return [
'code' => 1,
'msg' => '处理成功',
'data' => $result
];
} catch (Exception $e) {
Db::rollback();
throw new Exception($e->getMessage());
}
}
/**
* 添加奖池流水
* @param int $pool_type 奖池类型1-小 2-大
* @param int $type 流水类型1-累计 2-开奖 3-划转 4-释放
* @param float $amount 金额
* @param float $before_amount 操作前金额
* @param float $after_amount 操作后金额
* @param int $relate_id 关联ID
* @param int $times 轮次
* @param string $remark 备注
*/
private function addPoolFlow($pool_type, $type, $amount, $before_amount, $after_amount, $relate_id, $times, $remark)
{
Db::name('bb_lottery_pool_flow_5')->insert([
'pool_type' => $pool_type,
'type' => $type,
'amount' => $amount,
'before_amount' => $before_amount,
'after_amount' => $after_amount,
'relate_id' => $relate_id,
'times' => $times, // 新增:写入轮次
'remark' => $remark,
'create_time' => time()
]);
}
/**
* 添加中奖记录
* @param int $uid 中奖用户ID
* @param int $prize_type 奖项类型1-小 2-大
* @param float $prize_amount 中奖金额
* @param float $pool_amount 奖池总金额
* @param int $ratio 中奖比例
* @param float $release_amount 释放金额
*/
private function addWinnerRecord($uid, $prize_type, $prize_amount, $pool_amount, $ratio, $release_amount)
{
Db::name('bb_lottery_winner_record')->insert([
'uid' => $uid,
'prize_type' => $prize_type,
'prize_amount' => $prize_amount,
'pool_amount' => $pool_amount,
'ratio' => $ratio,
'release_amount' => $release_amount,
'create_time' => time(),
'status' => 1 // 已发放
]);
// 此处可添加用户金币入账逻辑(如更新用户金币表)
}
/**
* 计算小奖中奖比例
* @param float $prize_amount 中奖金额
* @param float $pool_amount 奖池金额
* @return int 比例(%
*/
private function getSmallRatio($prize_amount, $pool_amount)
{
return intval(round($prize_amount / $pool_amount * 100));
}
/**
* 计算大奖中奖比例
* @param float $prize_amount 中奖金额
* @param float $pool_amount 奖池金额
* @return int 比例(%
*/
private function getBigRatio($prize_amount, $pool_amount)
{
return intval(round($prize_amount / $pool_amount * 100));
}
/**
* 统计中奖数据
* @param array $where 筛选条件如uid、prize_type、time
* @return array 统计结果
*/
public function statWinner($where = [])
{
$query = Db::name('bb_lottery_winner_record');
if (!empty($where['uid'])) {
$query->where('uid', $where['uid']);
}
if (!empty($where['prize_type'])) {
$query->where('prize_type', $where['prize_type']);
}
if (!empty($where['start_time']) && !empty($where['end_time'])) {
$query->whereBetween('create_time', [$where['start_time'], $where['end_time']]);
}
// 总中奖金额、总释放金额、中奖次数
$stat = $query->field([
'SUM(prize_amount) as total_prize',
'SUM(release_amount) as total_release',
'COUNT(id) as total_times'
])->find();
return [
'total_prize' => $stat['total_prize'] ?? 0,
'total_release' => $stat['total_release'] ?? 0,
'total_times' => $stat['total_times'] ?? 0
];
}
}