endTime then redis.call('HSET', redpacketKey, 'status', 2) return {0, "红包已结束", 0} end -- 检查是否已经抢过 local hasGrabbed = redis.call('SISMEMBER', userSetKey, userId) if hasGrabbed == 1 then return {0, "已经抢过该红包", 0} end -- 检查是否还有剩余 local leftAmount = tonumber(redpacket['left_amount']) local leftCount = tonumber(redpacket['left_count']) if leftCount <= 0 or leftAmount <= 0 then return {0, "红包已抢完", 0} end -- 计算红包金额(核心修复:解决3金币2红包场景第二个红包为0的问题) local amount = 0 local isFinished = 0 if leftCount == 1 then -- 最后一个红包,获得剩余所有金额(确保至少1) amount = leftAmount isFinished = 1 else -- 随机算法:二倍均值法(适配整数+保底逻辑,彻底避免0) -- 1. 基础二倍均值(整数处理) local avg = leftAmount / leftCount local maxAmount = math.floor(avg * 2) -- 2. 核心修复:保底限制 - 最大金额不能超过「剩余金额 - (剩余个数 - 1)」 -- 确保剩下的每个红包至少能分到1个金币(比如3金币2红包:3 - (2-1) = 2,第一个红包最多抢2) local safeMax = leftAmount - (leftCount - 1) maxAmount = math.min(maxAmount, safeMax) -- 3. 强制保证最小金额为1,最大金额不小于1 maxAmount = math.max(maxAmount, 1) -- 4. 随机生成1到maxAmount之间的整数(绝对不会出现0) amount = math.random(1, maxAmount) -- 5. 整数场景下的抢完判断(无需浮点数误差处理) if (leftCount - 1) == 1 and (leftAmount - amount) == 0 then isFinished = 1 end end -- 更新红包数据(整数处理,无小数) local newLeftAmount = leftAmount - amount local newLeftCount = leftCount - 1 redis.call('HSET', redpacketKey, 'left_amount', newLeftAmount) redis.call('HSET', redpacketKey, 'left_count', newLeftCount) -- 标记用户已抢 redis.call('SADD', userSetKey, userId) -- 如果抢完了,更新状态为已结束(2) if isFinished == 1 then redis.call('HSET', redpacketKey, 'status', 2) end return {1, tostring(amount), isFinished} LUA; } }