Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
2025-12-21 20:01:54 +08:00
5 changed files with 216 additions and 27 deletions

View File

@@ -189,7 +189,8 @@ class Room extends BaseCom
$pit_number = input('pit_number', 0);
$heart_id = input('heart_id', 0);
if($gift_id == 88){
$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);
}else{
$reslut = model('Room')->room_gift($this->uid, $to_uid, $gift_id, $gift_num, $type, $room_id, $pit_number,$heart_id);

View File

@@ -2,6 +2,7 @@
namespace app\api\model;
use app\common\controller\Push;
use app\common\service\LotteryService;
use think\Db;
use think\Exception;
@@ -23,8 +24,11 @@ class Lottery extends Model
if(in_array($send_uid,$toarray)){
return ['code' => 0, 'msg' => '收礼人不能包含自己', 'data' => null];
}
//获取礼物信息
$gift_info = Db::name('vs_gift')->where(['gid'=>$gift_id])
->field('gid as gift_id,gift_name,gift_price,file_type,base_image,play_image,gift_type,label,is_public_server')->find();
//送给所有人的总价格
$all_gift_price = $gift_info['gift_price'] * $num * count($toarray);
//判断是否有足够的金币
@@ -40,7 +44,7 @@ class Lottery extends Model
$FromUserInfo['chat_bubble'] = model('Decorate')->user_decorate_detail($send_uid,9);//聊天气泡
$nums = $num * count($toarray);
$ress = $this->lottery($send_uid,$gift_info['gift_price'],$nums,$room_id,$gift_id,$FromUserInfo);
$ress = $this->lottery($send_uid,$gift_info['gift_price'],$nums,$room_id,$gift_id,$FromUserInfo,$gift_info);
if($ress['code'] == 0){
return ['code' => 0, 'msg' => $ress['msg'], 'data' => null];
}
@@ -126,8 +130,10 @@ class Lottery extends Model
//抽奖
public function lottery($send_uid,$gift_price,$num,$room_id,$giftId,$fromUserInfo=null)
public function lottery($send_uid,$gift_price,$num,$room_id,$giftId,$fromUserInfo=null,$gift_info=null)
{
$big_prize_play_image = db::name('bb_lottery_config')->where(['key' => 'big_prize_play_image'])->value('value');
$small_prize_play_image = db::name('bb_lottery_config')->where(['key' => 'small_prize_play_image'])->value('value');
try {
for($i=0;$i<$num;$i++){
$gift_gold = $gift_price;
@@ -141,30 +147,46 @@ class Lottery extends Model
} else {//开奖
// 大奖
if ($result['is_big_prize'] == 1) {//$result['big_prize_amount'],//中奖金额
$wallet_update = model('api/GiveGift')->change_user_cion_or_earnings_log($send_uid,$result['big_prize_amount'],$room_id,1,58,'用户幸运币爆大币');
if(!$wallet_update){
return ['code' => 0, 'msg' => '流水记录失败', 'data' => null];
}
$beilv = floor($result['big_prize_amount'] / $gift_price);
$tet['text'] = '恭喜用户'.$fromUserInfo['nickname'].'幸运币活动获得幸运币'.$beilv.'倍';
$tet['type'] = 1;
$tet['beilv'] = $beilv;
$tet['play_image'] = 'https://cos.xscmmidi.site/admin/4676520chepiao_17613610239812.mp4';
} else { // 小奖 $result['small_prize_amount'],//中奖金额
$wallet_update = model('api/GiveGift')->change_user_cion_or_earnings_log($send_uid,$result['small_prize_amount'],$room_id,1,58,'用户幸运币爆小币');
$wallet_update = model('api/GiveGift')->change_user_cion_or_earnings_log($send_uid,$result['big_prize_amount'],$room_id,1,58,'参与幸运币活动获得'.$beilv.'倍');
if(!$wallet_update){
return ['code' => 0, 'msg' => '流水记录失败', 'data' => null];
}
$tet['text'] = '恭喜用户'.$fromUserInfo['nickname'].'在幸运币活动中获得幸运币'.$beilv.'倍';
$tet['type'] = 1;
$tet['beilv'] = $beilv;
$tet['play_image'] = $big_prize_play_image;
} else { // 小奖 $result['small_prize_amount'],//中奖金额
$beilv = floor($result['small_prize_amount'] / $gift_price);
$wallet_update = model('api/GiveGift')->change_user_cion_or_earnings_log($send_uid,$result['small_prize_amount'],$room_id,1,58,'参与幸运币活动获得'.$beilv.'倍');
if(!$wallet_update){
return ['code' => 0, 'msg' => '流水记录失败', 'data' => null];
}
$tet['text'] = '恭喜用户'.$fromUserInfo['nickname'].'在幸运币活动中获得幸运币'.$beilv.'倍';
$tet['type'] = 2;
$tet['beilv'] = $beilv;
$tet['play_image'] = 'https://cos.xscmmidi.site/admin/4652maomaojingling_17613603758950.mp4';
$tet['play_image'] = $small_prize_play_image;
}
$tet['FromUserInfo'] = $fromUserInfo;
$tet['user_id'] = $send_uid;
model('api/Chat')->sendMsg(1100,$room_id,$tet);
$push = new Push($send_uid, $room_id);
$room_name = Db::name('vs_room')->where(['id' => $room_id, 'apply_status' => 2])->value('room_name');
$text = '恭喜'.$fromUserInfo['nickname'] . '在' . $room_name . '房间获得幸运币'. $beilv . '倍';
$text_list_new[] = [
'text' => $text,
'gift_picture' => $gift_info['base_image'],
'room_id' => $room_id,
'fromUserName' => $fromUserInfo['nickname'],
'toUserName' => '',
'giftName' => '',
'roomId' => $room_id,
'number' => 1,
];
$push->giftBanner($text_list_new);
}
}
}

View File

@@ -51,10 +51,10 @@ class UserWallet extends Model
// 8.礼盒奖励 9.房间补贴 10.购买礼物 11.收礼增加收益 12.工会补贴 13.转赠金币(接收) 14.收益兑换
// 15.首充 16.天降好礼充值 17.退出工会扣款 18.房主收益 19.主持人收益20.发布头条扣除余额,21.公会长收益,22.提现驳回或提现失败返还,23.财富等级奖励金币领取,24.删除关系扣金币
//27.小时榜获得28-新人充值好礼,32-发红包金币29-发红包钻石30-抢红包金币31-抢红包(钻石) 33-红包剩余退回金币34-红包剩余退回(钻石)
//50-签约 51-签约失败退回,52-首次被签约收入 53-师徒签到 54-叛徒补偿,55-徒弟收礼返佣56-续约
//50-签约 51-签约失败退回,52-首次被签约收入 53-师徒签到 54-叛徒补偿,55-徒弟收礼返佣56-续约,57签到58爆币
if($gift_type == 1){ //1金币2收益钻石
if($in_out_type == 1){//1收入
$in_out_types = [2,5,6,8,13,14,15,16,22,23,26,27,30,28,33,51,57];
$in_out_types = [2,5,6,8,13,14,15,16,22,23,26,27,30,28,33,51,57,58];
}elseif($in_out_type == 2){//2支出
$in_out_types = [4,7,10,17,20,24,25,32,50,56];
}

View File

@@ -126,6 +126,148 @@ if small_total_times >= small_trigger_times then
end
end
-- 返回结果
return cjson.encode(result)
LUA;
}
// 获取Lua脚本
public static function getLotteryLuaScripts()
{
return <<<LUA
-- 接收参数:
-- send_uid, recv_uid, gift_gold, small_trigger_times, big_threshold,
-- small_round, big_round, big_total_gold,
-- big_weight_60, big_weight_70, big_weight_80, big_weight_total
local send_uid = ARGV[1]
local recv_uid = ARGV[2]
local gift_gold = tonumber(ARGV[3])
local small_trigger_times = tonumber(ARGV[4])
local big_threshold = tonumber(ARGV[5])
local small_round = tonumber(ARGV[6])
local big_round = tonumber(ARGV[7])
local big_total_gold = tonumber(ARGV[8])
local big_weight_60 = tonumber(ARGV[9])
local big_weight_70 = tonumber(ARGV[10])
local big_weight_80 = tonumber(ARGV[11])
local big_weight_total = tonumber(ARGV[12])
-- 核心约束:强制小轮次 ≥ 大轮次
if small_round < big_round then
small_round = big_round
end
-- 1. 基础金额拆分
local recv_gold = gift_gold * 0.5
local small_pool_add = gift_gold * 0.5
-- 2. Redis键定义
local small_round_key = "lottery:small_pool:round"
local small_total_times_key = "lottery:small_pool:total_times"
local small_total_gold_key = "lottery:small_pool:total_gold"
local big_round_key = "lottery:big_pool:round"
local big_total_gold_key = "lottery:big_pool:total_gold"
-- 初始化轮次
redis.call('set', small_round_key, small_round)
redis.call('set', big_round_key, big_round)
if big_total_gold == 0 or big_total_gold == nil then
big_total_gold = tonumber(redis.call('get', big_total_gold_key) or 0)
end
-- 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 = math.floor((small_total_gold + small_pool_add) * 100) / 100
redis.call('set', small_total_gold_key, small_total_gold)
-- 4. 返回结果初始化
local result = {
send_uid = send_uid,
recv_uid = recv_uid,
gift_gold = gift_gold,
recv_gold = recv_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_remain_amount = 0,
is_big_prize = 0,
big_prize_amount = 0,
big_release_amount = 0,
small_round = small_round,
big_round = big_round,
big_total_gold = big_total_gold,
small_prize_to_big_next_round = 0,
big_ratio = 0,
-- ===================== 新增核心字段 =====================
big_pool_total_before_open = 0 -- 大奖开奖前的奖池总金额
-- ======================================================
}
-- 5. 小奖池开奖判断
if small_total_times >= small_trigger_times then
result.is_small_prize = 1
-- 小奖随机比例
local small_ratio = math.random(1, 99)
result.small_prize_amount = math.floor(small_total_gold * small_ratio / 100 * 100) / 100
result.small_remain_amount = math.floor((small_total_gold - result.small_prize_amount) * 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
-- 6. 小奖剩余划入大奖池当前轮次
big_total_gold = math.floor((big_total_gold + result.small_remain_amount) * 100) / 100
redis.call('set', big_total_gold_key, big_total_gold)
result.big_total_gold = big_total_gold
-- 7. 大奖池开奖判断
if big_total_gold >= big_threshold then
-- ===================== 关键修改:记录开奖前总金额 =====================
result.big_pool_total_before_open = big_total_gold -- 保存开奖前的总金额
-- ======================================================
result.is_big_prize = 1
-- 从配置读取权重计算出奖比例
local random_weight = math.random(1, big_weight_total)
local big_ratio = 60
if random_weight > big_weight_60 and random_weight <= (big_weight_60 + big_weight_70) then
big_ratio = 70
elseif random_weight > (big_weight_60 + big_weight_70) then
big_ratio = 80
end
result.big_ratio = big_ratio
-- 大奖金额计算(基于开奖前的总金额)
result.big_prize_amount = math.floor(result.big_pool_total_before_open * big_ratio / 100 * 100) / 100
result.big_release_amount = math.floor((result.big_pool_total_before_open - result.big_prize_amount) * 100) / 100
-- 重置大奖池,大轮次+1
redis.call('set', big_total_gold_key, 0)
big_round = big_round + 1
redis.call('set', big_round_key, big_round)
if small_round < big_round then
small_round = big_round
redis.call('set', small_round_key, small_round)
result.small_round = small_round
end
result.big_round = big_round
result.big_total_gold = 0
-- 小奖开奖金额划入大奖池下一轮
result.small_prize_to_big_next_round = result.small_prize_amount
local new_big_total_gold = math.floor(result.small_prize_amount * 100) / 100
redis.call('set', big_total_gold_key, new_big_total_gold)
result.big_total_gold = new_big_total_gold
end
end
-- 返回结果
return cjson.encode(result)
LUA;

View File

@@ -12,6 +12,7 @@ class LotteryService
private $redis;
// 配置参数
private $config;
private $bigPrizeWeights;
public function __construct()
{
@@ -19,10 +20,31 @@ class LotteryService
// 加载配置
$this->config = Db::name('bb_lottery_config')->column('value', 'key');
// 初始化Redis缓存若Redis数据丢失从数据库恢复
$this->initBigPrizeWeights();
$this->initRedisFromDb();
$this->checkRoundConstraint();
}
private function initBigPrizeWeights()
{
$this->bigPrizeWeights = [
'60' => intval($this->config['big_prize_ratio_60_weight'] ?? 20),
'70' => intval($this->config['big_prize_ratio_70_weight'] ?? 50),
'80' => intval($this->config['big_prize_ratio_80_weight'] ?? 30)
];
$this->bigPrizeWeights['total'] = array_sum($this->bigPrizeWeights);
}
private function checkRoundConstraint()
{
$small_round = intval($this->redis->get('lottery:small_pool:round') ?: 1);
$big_round = intval($this->redis->get('lottery:big_pool:round') ?: 1);
if ($small_round < $big_round) {
$this->redis->set('lottery:small_pool:round', $big_round);
}
}
/**
* 缓存恢复:独立恢复大小轮次+对应金额
*/
@@ -61,10 +83,8 @@ class LotteryService
$bigAddGold = Db::name('bb_lottery_pool_flow')
->where(['pool_type' => 2, 'type' => 3, 'times' => $big_round])
->sum('amount') ?: 0;
$bigReduceGold = Db::name('bb_lottery_pool_flow')
->where(['pool_type' => 2, 'type' => ['in',[2,4]], 'times' => $big_round])
->sum('amount') ?: 0;
$this->redis->set('lottery:big_pool:total_gold', $bigAddGold + $bigReduceGold);
$this->redis->set('lottery:big_pool:total_gold', $bigAddGold );
}
}
@@ -92,13 +112,17 @@ class LotteryService
$big_total_gold = floatval($this->redis->get('lottery:big_pool:total_gold') ?: 0);
// 加载Lua脚本
$luaSha = LotteryGiftLua::getLotteryLuaScript();
$luaSha = LotteryGiftLua::getLotteryLuaScripts();
// 执行Lua脚本入参small_round + big_round
$result = $this->redis->eval($luaSha, [
$send_uid, 0, $gift_gold,
$small_trigger_times, $big_threshold,
$small_round, $big_round, $big_total_gold
$small_round, $big_round, $big_total_gold,
$this->bigPrizeWeights['60'],
$this->bigPrizeWeights['70'],
$this->bigPrizeWeights['80'],
$this->bigPrizeWeights['total']
], 0);
// var_dump($result);die;
$result = json_decode($result, true);
@@ -143,8 +167,8 @@ class LotteryService
$winnerUid,
2, // 大奖
$result['big_prize_amount'],//中奖金额
$result['big_total_gold'], // 开奖时大奖池金额
$this->getBigRatio($result['big_prize_amount'], $result['big_total_gold']),
$result['big_pool_total_before_open'], // 开奖时大奖池金额
$result['big_ratio'],
$result['big_release_amount']//释放金额
);
@@ -152,8 +176,8 @@ class LotteryService
$this->addPoolFlow(
2, // 大奖池
4, // 释放
-$result['big_release_amount'],//释放金额
$result['big_total_gold'],// 开奖时大奖池金额
$result['big_release_amount'],//释放金额
$result['big_pool_total_before_open'],// 开奖时大奖池金额
0,
$giftId,
$result['big_round'] - 1, // 关联已结束的小奖池轮次
@@ -186,7 +210,7 @@ class LotteryService
$this->addPoolFlow(
1, // 小奖池
2, // 开奖扣除
-$result['small_total_gold'],
$result['small_total_gold'],
$result['small_total_gold'],
0,
$giftId,