红包状态修改

This commit is contained in:
2025-10-14 18:09:49 +08:00
parent 7a57493a19
commit 4aac4e9109
4 changed files with 143 additions and 27 deletions

View File

@@ -22,7 +22,7 @@ local currentTime = tonumber(ARGV[1])
-- 检查红包是否存在
local redpacketData = redis.call('HGETALL', redpacketKey)
if not redpacketData or #redpacketData == 0 then
return {0, "红包不存在"}
return {0, "红包不存在", 0}
end
-- 将哈希数据转为table
@@ -38,27 +38,27 @@ local endTime = tonumber(redpacket['end_time'])
if status == 0 then
if currentTime < startTime then
return {0, "红包还未开始"}
return {0, "红包还未开始", 0}
else
-- 更新状态为进行中
-- 更新状态为进行中(1)
redis.call('HSET', redpacketKey, 'status', 1)
status = 1
end
end
-- if status ~= 1 then
-- return {0, "红包已结束"}
-- end
if status ~= 1 then
return {0, "红包已结束", 0}
end
-- if currentTime > endTime then
-- redis.call('HSET', redpacketKey, 'status', 2)
-- return {0, "红包已结束"}
-- end
if currentTime > 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, "已经抢过该红包"}
return {0, "已经抢过该红包", 0}
end
-- 检查是否还有剩余
@@ -66,14 +66,17 @@ local leftAmount = tonumber(redpacket['left_amount'])
local leftCount = tonumber(redpacket['left_count'])
if leftCount <= 0 or leftAmount <= 0 then
return {0, "红包已抢完"}
return {0, "红包已抢完", 0}
end
-- 计算红包金额
local amount = 0
local isFinished = 0
if leftCount == 1 then
-- 最后一个红包,获得剩余所有金额
amount = leftAmount
isFinished = 1
else
-- 随机算法:二倍均值法,保证公平性
local maxAmount = leftAmount / leftCount * 2
@@ -82,6 +85,10 @@ else
if amount > leftAmount then
amount = leftAmount
end
-- 检查是否是最后一个(由于浮点数计算可能有误差)
if leftCount == 1 or (leftAmount - amount) < 0.01 then
isFinished = 1
end
end
-- 更新红包数据
@@ -94,12 +101,14 @@ redis.call('HSET', redpacketKey, 'left_count', newLeftCount)
-- 标记用户已抢
redis.call('SADD', userSetKey, userId)
-- 如果抢完了,更新状态
if newLeftCount == 0 then
-- 如果抢完了,更新状态为已结束(2)
if isFinished == 1 then
redis.call('HSET', redpacketKey, 'status', 2)
end
return {1, tostring(amount)}
return {1, tostring(amount), isFinished}
LUA;
}
}

View File

@@ -32,6 +32,9 @@ class RedpacketService
*/
public function grabWithResult($redpacketId, $userId)
{
// 首先检查并更新红包状态
$this->checkAndUpdateRedpacketStatus($redpacketId);
$redpacketModel = new Redpacket();
$redpacket = $redpacketModel->getRedpacketInfo($redpacketId);
@@ -103,6 +106,7 @@ class RedpacketService
}
$amount = floatval($result[1]);
$isFinished = $result[2] == 1; // Lua脚本返回是否抢完
// Lua脚本执行成功记录到数据库
Db::startTrans();
@@ -142,12 +146,20 @@ class RedpacketService
Db::rollback();
}
// 更新红包剩余数量和金额
// 更新红包剩余数量和金额,如果抢完了更新状态
$updateData = [
'left_amount' => Db::raw('left_amount - ' . $amount),
'left_count' => Db::raw('left_count - 1'),
'updatetime' => time()
];
if ($isFinished) {
$updateData['status'] = Redpacket::STATUS_FINISHED;
}
Db::name('redpacket')
->where('id', $redpacketId)
->dec('left_amount', $amount)
->dec('left_count', 1)
->update();
->update($updateData);
Db::commit();
@@ -585,4 +597,67 @@ class RedpacketService
}
return true;
}
/**
* 检查并更新红包状态
* 在抢红包前调用,确保状态正确
*/
public function checkAndUpdateRedpacketStatus($redpacketId)
{
$redpacket = Db::name('redpacket')->where('id', $redpacketId)->find();
if (!$redpacket) {
return false;
}
$now = time();
$redis = Cache::store('redis')->handler();
$redpacketKey = "redpacket:{$redpacketId}";
// 如果红包状态为未开始(0),但当前时间已超过开始时间,则更新为进行中(1)
if ($redpacket['status'] == Redpacket::STATUS_PENDING && $now >= $redpacket['start_time']) {
Db::name('redpacket')
->where('id', $redpacketId)
->update([
'status' => Redpacket::STATUS_ACTIVE,
'updatetime' => $now
]);
// 更新Redis中的状态
$redis->hSet($redpacketKey, 'status', Redpacket::STATUS_ACTIVE);
return true;
}
// 如果红包状态为进行中(1),但已抢完,则更新为已结束(2)
if ($redpacket['status'] == Redpacket::STATUS_ACTIVE && $redpacket['left_count'] <= 0) {
Db::name('redpacket')
->where('id', $redpacketId)
->update([
'status' => Redpacket::STATUS_FINISHED,
'updatetime' => $now
]);
// 更新Redis中的状态
$redis->hSet($redpacketKey, 'status', Redpacket::STATUS_FINISHED);
return true;
}
// 如果红包状态为进行中(1),但已超过结束时间,则更新为已结束(2)
if ($redpacket['status'] == Redpacket::STATUS_ACTIVE && $now > $redpacket['end_time']) {
Db::name('redpacket')
->where('id', $redpacketId)
->update([
'status' => Redpacket::STATUS_FINISHED,
'updatetime' => $now
]);
// 更新Redis中的状态
$redis->hSet($redpacketKey, 'status', Redpacket::STATUS_FINISHED);
return true;
}
return false;
}
}