本次优化对 LotteryChanceService
进行了全面的重构和优化,主要包括:
shop_lottery_user_chance_record
替代原有的 JSON 字段存储,使用独立表记录用户获取抽奖机会的详细信息:
CREATE TABLE `shop_lottery_user_chance_record` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '记录ID',
`activity_id` int(11) NOT NULL COMMENT '活动ID',
`user_id` int(11) NOT NULL COMMENT '用户ID',
`get_type` tinyint(1) NOT NULL COMMENT '获取类型: 1=购买指定商品 2=单笔订单消费满额 3=单次充值满额 4=活动期间累计消费满额 5=管理员赠送',
`chances` int(11) NOT NULL DEFAULT '1' COMMENT '获得机会次数',
`condition_id` int(11) DEFAULT NULL COMMENT '条件ID(关联lottery_condition表)',
`condition_value` decimal(10,2) DEFAULT NULL COMMENT '条件值(金额或商品ID)',
`order_id` int(11) DEFAULT NULL COMMENT '订单ID(订单触发时)',
`recharge_amount` decimal(10,2) DEFAULT NULL COMMENT '充值金额(充值触发时)',
`admin_id` int(11) DEFAULT NULL COMMENT '管理员ID(管理员赠送时)',
`reason` varchar(255) DEFAULT NULL COMMENT '赠送原因(管理员赠送时)',
`remark` varchar(500) DEFAULT NULL COMMENT '备注信息',
`get_time` int(11) NOT NULL COMMENT '获得时间',
`createtime` int(11) NOT NULL COMMENT '创建时间',
`updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_activity_user` (`activity_id`,`user_id`),
KEY `idx_get_type` (`get_type`),
KEY `idx_get_time` (`get_time`),
KEY `idx_condition_id` (`condition_id`),
KEY `idx_order_id` (`order_id`),
KEY `idx_admin_id` (`admin_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户抽奖机会获取记录表';
核心表:
shop_lottery_activity
- 抽奖活动主表shop_lottery_condition
- 参与条件表shop_lottery_user_chance
- 用户抽奖机会表shop_lottery_user_chance_record
- 用户抽奖机会获取记录表(新增)抽奖相关表:
shop_lottery_prize
- 抽奖奖品表shop_lottery_draw_record
- 用户抽奖记录表shop_lottery_win_record
- 中奖记录表shop_lottery_statistics
- 活动统计表保留的常量(用于后台渲染):
// ============ 触发类型 ============
const TRIGGER_TYPE_BUY_GOODS = 1; // 购买商品
const TRIGGER_TYPE_ORDER_CONSUME = 2; // 订单消费
const TRIGGER_TYPE_RECHARGE = 3; // 充值
const TRIGGER_TYPE_TOTAL_CONSUME = 4; // 累计消费
机会获取类型(与条件类型保持一致):
// ============ 机会获取类型(与条件类型保持一致,额外增加管理员赠送) ============
const CHANCE_GET_TYPE_BUY_GOODS = 1; // 购买指定商品(对应CONDITION_TYPE_BUY_GOODS)
const CHANCE_GET_TYPE_ORDER_AMOUNT = 2; // 单笔订单消费满额(对应CONDITION_TYPE_ORDER_AMOUNT)
const CHANCE_GET_TYPE_RECHARGE = 3; // 单次充值满额(对应CONDITION_TYPE_RECHARGE_AMOUNT)
const CHANCE_GET_TYPE_TOTAL_AMOUNT = 4; // 活动期间累计消费满额(对应CONDITION_TYPE_TOTAL_AMOUNT)
const CHANCE_GET_TYPE_ADMIN_GRANT = 5; // 管理员赠送
LotteryEnum
中管理const DEFAULT_BATCH_SIZE = 100; // 默认批量处理数量
const MAX_BATCH_SIZE = 1000; // 最大批量处理数量
private static function getChanceGetTypeFromDetail($detail)
{
// 直接根据条件类型确定获取类型
if (isset($detail['condition_type'])) {
switch ($detail['condition_type']) {
case LotteryEnum::CONDITION_TYPE_BUY_GOODS:
return LotteryEnum::CHANCE_GET_TYPE_BUY_GOODS;
case LotteryEnum::CONDITION_TYPE_ORDER_AMOUNT:
return LotteryEnum::CHANCE_GET_TYPE_ORDER_AMOUNT;
case LotteryEnum::CONDITION_TYPE_RECHARGE_AMOUNT:
return LotteryEnum::CHANCE_GET_TYPE_RECHARGE;
case LotteryEnum::CONDITION_TYPE_TOTAL_AMOUNT:
return LotteryEnum::CHANCE_GET_TYPE_TOTAL_AMOUNT;
}
}
// 检查是否是管理员赠送
if (isset($detail['admin_id']) && $detail['admin_id'] > 0) {
return LotteryEnum::CHANCE_GET_TYPE_ADMIN_GRANT;
}
return LotteryEnum::CHANCE_GET_TYPE_ADMIN_GRANT;
}
public static function addChance($activityId, $userId, $times = 1, $detail = [])
{
try {
Db::startTrans();
// 更新用户机会总数
$chance = static::updateUserChance($activityId, $userId, $times);
// 创建详细记录
$recordData = [
'activity_id' => $activityId,
'user_id' => $userId,
'get_type' => static::getChanceGetTypeFromDetail($detail),
'chances' => $times,
// ... 其他字段
];
LotteryUserChanceRecord::create($recordData);
Db::commit();
return $chance;
} catch (Exception $e) {
Db::rollback();
throw $e;
}
}
主要功能:
关键方法:
// 获取用户机会获取记录
LotteryUserChanceRecord::getUserChanceRecords($activityId, $userId, $page, $limit);
// 获取活动机会获取统计
LotteryUserChanceRecord::getActivityChanceStats($activityId);
// 获取用户机会获取统计
LotteryUserChanceRecord::getUserChanceStats($userId, $activityId);
// 批量创建记录
LotteryUserChanceRecord::batchCreateRecords($records);
// 数据验证
LotteryUserChanceRecord::validateRecord($data);
/**
* 手动给用户增加抽奖机会(管理员操作)
*/
public static function manualGrantChance($activityId, $userId, $chances, $reason = '', $adminId = 0)
{
// 参数验证
if ($chances <= 0) {
throw new Exception('抽奖机会数量必须大于0');
}
// 活动和用户验证
$activity = LotteryActivity::find($activityId);
$user = User::find($userId);
// 构建详情(不包含trigger_type字段)
$detail = [
'reason' => $reason,
'admin_id' => $adminId,
'granted_time' => time()
];
return static::grantChanceToUser($activityId, $userId, $chances, $detail);
}
// 获取用户机会详情(包含记录)
public static function getUserChanceDetail($activityId, $userId)
{
$userChance = static::getUserChance($activityId, $userId);
if (!$userChance) {
return [
'total_chances' => 0,
'used_chances' => 0,
'remain_chances' => 0,
'get_records' => []
];
}
// 获取机会获得记录
$getRecords = LotteryUserChanceRecord::getUserChanceRecords($activityId, $userId);
return [
'total_chances' => $userChance->total_chances,
'used_chances' => $userChance->used_chances,
'remain_chances' => $userChance->remain_chances,
'last_get_time' => $userChance->last_get_time,
'last_use_time' => $userChance->last_use_time,
'get_records' => $getRecords
];
}
// 获取用户机会获取记录
public static function getUserChanceRecords($activityId, $userId, $page = 1, $limit = 20);
// 获取活动机会获取统计
public static function getActivityChanceRecordStats($activityId);
// 获取用户机会获取统计
public static function getUserChanceRecordStats($userId, $activityId = null);
// 批量创建机会获取记录
public static function batchCreateChanceRecords($records);
// 验证机会获取记录数据
public static function validateChanceRecord($data);
try {
Db::startTrans();
// 更新用户机会表
$this->updateUserChance();
// 创建获取记录
$this->createChanceRecord();
Db::commit();
} catch (Exception $e) {
Db::rollback();
throw $e;
}
$orderInfo = [
'id' => 123,
'total_amount' => 100.00,
'goods' => [
['goods_id' => 1],
['goods_id' => 2]
]
];
$grantedChances = LotteryChanceService::checkAndGrantChanceForOrder($orderInfo, $userId);
// 返回结果示例
[
[
'activity_id' => 1,
'activity_name' => '双11抽奖活动',
'chances' => 2,
'granted_time' => 1699123456
]
]
$rechargeInfo = [
'amount' => 50.00,
'type' => 'recharge'
];
$grantedChances = LotteryChanceService::checkAndGrantChanceForRecharge($rechargeInfo, $userId);
// 管理员给用户赠送抽奖机会
$result = LotteryChanceService::manualGrantChance(
$activityId, // 活动ID
$userId, // 用户ID
5, // 赠送机会数
'用户反馈奖励', // 赠送原因
$adminId // 管理员ID
);
// 获取用户在指定活动中的机会获取记录
$records = LotteryChanceService::getUserChanceRecords($activityId, $userId, 1, 20);
// 获取用户机会获取统计
$stats = LotteryChanceService::getUserChanceRecordStats($userId, $activityId);
// 返回结果示例
[
'total_records' => 5,
'total_chances' => 8,
'type_stats' => [
1 => ['type' => 1, 'type_text' => '购买指定商品', 'count' => 2, 'chances' => 3],
2 => ['type' => 2, 'type_text' => '单笔订单消费满额', 'count' => 2, 'chances' => 3],
5 => ['type' => 5, 'type_text' => '管理员赠送', 'count' => 1, 'chances' => 2]
],
'recent_records' => [...]
]
// 获取活动的机会获取统计
$stats = LotteryChanceService::getActivityChanceRecordStats($activityId);
// 返回结果示例
[
'total_records' => 150,
'total_chances' => 230,
'type_stats' => [
1 => ['type' => 1, 'type_text' => '购买指定商品', 'count' => 50, 'chances' => 75],
2 => ['type' => 2, 'type_text' => '单笔订单消费满额', 'count' => 80, 'chances' => 120],
3 => ['type' => 3, 'type_text' => '单次充值满额', 'count' => 15, 'chances' => 25],
5 => ['type' => 5, 'type_text' => '管理员赠送', 'count' => 5, 'chances' => 10]
]
]
shop_lottery_user_chance
表的 get_detail
字段保留但不使用// 从 get_detail JSON 字段迁移到独立记录表
public static function migrateFromJsonToTable()
{
$userChances = LotteryUserChance::where('get_detail', 'neq', '')->select();
foreach ($userChances as $userChance) {
$getDetails = json_decode($userChance->get_detail, true);
if (empty($getDetails)) continue;
foreach ($getDetails as $detail) {
// 创建新的记录
LotteryUserChanceRecord::create([
'activity_id' => $userChance->activity_id,
'user_id' => $userChance->user_id,
'get_type' => static::parseOldTriggerType($detail),
'chances' => $detail['chances'] ?? 1,
// ... 其他字段映射
]);
}
}
}
本次优化实现了以下主要目标:
整体上,优化后的系统具有更好的性能、可维护性和扩展性,为后续的功能开发奠定了良好的基础。