红包状态修改
This commit is contained in:
@@ -39,6 +39,8 @@ class Redpacket extends BaseCom
|
||||
}
|
||||
|
||||
$service = new RedpacketService();
|
||||
// 在抢红包前确保状态正确
|
||||
$service->checkAndUpdateRedpacketStatus($redpacketId);
|
||||
$reslut = $service->grabWithResult($redpacketId, $this->uid);
|
||||
|
||||
return V($reslut['code'], $reslut['msg'], $reslut['data']);
|
||||
@@ -77,6 +79,8 @@ class Redpacket extends BaseCom
|
||||
}
|
||||
|
||||
$service = new RedpacketService();
|
||||
// 在获取详情前确保状态正确
|
||||
$service->checkAndUpdateRedpacketStatus($redpacketId);
|
||||
$detail = $service->getDetail($redpacketId, $this->uid);
|
||||
|
||||
if (!$detail) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -240,9 +240,36 @@ class PerformPerSecond
|
||||
*/
|
||||
public function processExpiredRedpackets()
|
||||
{
|
||||
// 查找已结束但未退款的红包
|
||||
$now = time();
|
||||
$processedCount = 0;
|
||||
|
||||
// 1. 处理到时间的未开始红包,更新为进行中
|
||||
$pendingRedpackets = Db::name('redpacket')
|
||||
->where('status', Redpacket::STATUS_PENDING)
|
||||
->where('start_time', '<=', $now)
|
||||
->select();
|
||||
|
||||
foreach ($pendingRedpackets as $redpacket) {
|
||||
Db::name('redpacket')
|
||||
->where('id', $redpacket['id'])
|
||||
->update([
|
||||
'status' => Redpacket::STATUS_ACTIVE,
|
||||
'updatetime' => $now
|
||||
]);
|
||||
|
||||
// 更新Redis缓存
|
||||
$redis = Cache::store('redis')->handler();
|
||||
$redisKey = "redpacket:{$redpacket['id']}";
|
||||
$redis->hSet($redisKey, 'status', Redpacket::STATUS_ACTIVE);
|
||||
|
||||
$processedCount++;
|
||||
}
|
||||
|
||||
// 2. 处理已过期的进行中红包,更新为已结束并退款
|
||||
$expiredRedpackets = Db::name('redpacket')
|
||||
->where(['end_time' => ['<',time()], 'status' => 1])
|
||||
->where('status', Redpacket::STATUS_ACTIVE)
|
||||
->where('end_time', '<', $now)
|
||||
->where('left_count', '>', 0)
|
||||
->select();
|
||||
|
||||
foreach ($expiredRedpackets as $redpacket) {
|
||||
@@ -276,27 +303,28 @@ class PerformPerSecond
|
||||
}
|
||||
}
|
||||
|
||||
// 更新红包状态
|
||||
// 更新红包状态为已结束
|
||||
Db::name('redpacket')
|
||||
->where('id', $redpacket['id'])
|
||||
->update([
|
||||
'status' => 3,
|
||||
'updatetime' => time()
|
||||
'status' => Redpacket::STATUS_FINISHED,
|
||||
'updatetime' => $now
|
||||
]);
|
||||
|
||||
// 清理Redis缓存
|
||||
// 更新Redis缓存
|
||||
$redis = Cache::store('redis')->handler();
|
||||
$redisKey = "redpacket:{$redpacket['id']}";
|
||||
$redis->del($redisKey);
|
||||
$redis->hSet($redisKey, 'status', Redpacket::STATUS_FINISHED);
|
||||
|
||||
Db::commit();
|
||||
|
||||
$processedCount++;
|
||||
} catch (\Exception $e) {
|
||||
Db::rollback();
|
||||
// 记录日志
|
||||
\think\Log::error("红包退款失败: {$redpacket['id']}, 错误: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
echo "处理过期红包-共". $processedCount . "条数据\n";
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user