PHP 勋章自动发放逻辑

wen PHP项目 7

我将为您设计一个PHP勋章自动发放系统,包含完整的逻辑和代码实现。

PHP 勋章自动发放逻辑

勋章自动发放系统设计

数据库设计

-- 勋章表
CREATE TABLE `badges` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL COMMENT '勋章名称',
  `code` varchar(50) NOT NULL COMMENT '勋章唯一标识',
  `description` varchar(255) DEFAULT NULL COMMENT '勋章描述',
  `icon` varchar(255) DEFAULT NULL COMMENT '勋章图标路径',
  `conditions` text NOT NULL COMMENT '发放条件(JOSN格式)',
  `status` tinyint(1) DEFAULT '1' COMMENT '状态:1启用 0禁用',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 用户勋章表
CREATE TABLE `user_badges` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL COMMENT '用户ID',
  `badge_id` int(11) NOT NULL COMMENT '勋章ID',
  `earned_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '获得时间',
  `source` varchar(50) DEFAULT NULL COMMENT '获得来源',
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_user_badge` (`user_id`, `badge_id`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_badge_id` (`badge_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 用户操作日志表(用于统计)
CREATE TABLE `user_actions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `action_type` varchar(50) NOT NULL COMMENT '操作类型',
  `action_data` text DEFAULT NULL COMMENT '操作数据(JSON)',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_user_action` (`user_id`, `action_type`),
  KEY `idx_created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

核心类实现

<?php
class BadgeManager {
    private $db;
    private $cache;
    public function __construct($db, $cache = null) {
        $this->db = $db;
        $this->cache = $cache ?: new RedisCache(); // 或者使用文件缓存
    }
    /**
     * 检查并发放勋章
     */
    public function checkAndAward($userId, $actionType = null) {
        // 获取所有启用的勋章
        $badges = $this->getAllEnabledBadges();
        $awardedBadges = [];
        foreach ($badges as $badge) {
            // 跳过已获得的勋章
            if ($this->hasBadge($userId, $badge['id'])) {
                continue;
            }
            // 解析条件并检查
            $conditions = json_decode($badge['conditions'], true);
            if ($this->checkConditions($userId, $badge, $conditions, $actionType)) {
                $this->awardBadge($userId, $badge['id'], $actionType);
                $awardedBadges[] = $badge;
            }
        }
        return $awardedBadges;
    }
    /**
     * 获取所有启用的勋章
     */
    private function getAllEnabledBadges() {
        $cacheKey = 'all_enabled_badges';
        $badges = $this->cache->get($cacheKey);
        if (!$badges) {
            $sql = "SELECT * FROM badges WHERE status = 1";
            $result = $this->db->query($sql);
            $badges = $result->fetch_all(MYSQLI_ASSOC);
            $this->cache->set($cacheKey, $badges, 3600); // 缓存1小时
        }
        return $badges;
    }
    /**
     * 检查用户是否已获得某勋章
     */
    private function hasBadge($userId, $badgeId) {
        $sql = "SELECT COUNT(*) as count FROM user_badges 
                WHERE user_id = ? AND badge_id = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->bind_param("ii", $userId, $badgeId);
        $stmt->execute();
        $result = $stmt->get_result();
        $row = $result->fetch_assoc();
        return $row['count'] > 0;
    }
    /**
     * 发放勋章
     */
    private function awardBadge($userId, $badgeId, $source) {
        $sql = "INSERT INTO user_badges (user_id, badge_id, source) 
                VALUES (?, ?, ?) 
                ON DUPLICATE KEY UPDATE id = id";
        $stmt = $this->db->prepare($sql);
        $stmt->bind_param("iis", $userId, $badgeId, $source);
        $stmt->execute();
        // 清除缓存
        $this->clearUserCache($userId);
        // 触发通知
        $this->notifyUser($userId, $badgeId);
    }
    /**
     * 检查发放条件
     */
    private function checkConditions($userId, $badge, $conditions, $actionType) {
        foreach ($conditions as $condition) {
            $result = $this->checkSingleCondition($userId, $badge, $condition);
            if (!$result) {
                return false;
            }
        }
        return true;
    }
    /**
     * 检查单个条件
     */
    private function checkSingleCondition($userId, $badge, $condition) {
        $type = $condition['type'];
        $value = $condition['value'];
        switch ($type) {
            case 'action_count':
                return $this->checkActionCount($userId, $condition['action_type'], $value);
            case 'continuous_days':
                return $this->checkContinuousDays($userId, $value);
            case 'total_days':
                return $this->checkTotalDays($userId, $value);
            case 'points':
                return $this->checkPoints($userId, $value);
            case 'level':
                return $this->checkUserLevel($userId, $value);
            case 'invite_count':
                return $this->checkInviteCount($userId, $value);
            case 'special_action':
                return $this->checkSpecialAction($userId, $condition['action_type']);
            default:
                return false;
        }
    }
    /**
     * 检查操作次数
     */
    private function checkActionCount($userId, $actionType, $requiredCount) {
        $cacheKey = "user_action_count_{$userId}_{$actionType}";
        $count = $this->cache->get($cacheKey);
        if ($count === false) {
            $sql = "SELECT COUNT(*) as count FROM user_actions 
                    WHERE user_id = ? AND action_type = ?";
            $stmt = $this->db->prepare($sql);
            $stmt->bind_param("is", $userId, $actionType);
            $stmt->execute();
            $result = $stmt->get_result();
            $row = $result->fetch_assoc();
            $count = $row['count'];
            $this->cache->set($cacheKey, $count, 600);
        }
        return $count >= $requiredCount;
    }
    /**
     * 检查连续签到天数
     */
    private function checkContinuousDays($userId, $requiredDays) {
        $sql = "SELECT created_at FROM user_actions 
                WHERE user_id = ? AND action_type = 'daily_checkin'
                ORDER BY created_at DESC LIMIT ?";
        $stmt = $this->db->prepare($sql);
        $stmt->bind_param("ii", $userId, $requiredDays);
        $stmt->execute();
        $result = $stmt->get_result();
        $dates = [];
        while ($row = $result->fetch_assoc()) {
            $dates[] = date('Y-m-d', strtotime($row['created_at']));
        }
        if (count($dates) < $requiredDays) {
            return false;
        }
        // 检查是否连续
        $start = strtotime($dates[0]);
        $expectedDate = $start;
        foreach ($dates as $date) {
            if (strtotime($date) != $expectedDate) {
                return false;
            }
            $expectedDate = strtotime('+1 day', $expectedDate);
        }
        return true;
    }
    /**
     * 检查总活跃天数
     */
    private function checkTotalDays($userId, $requiredDays) {
        $sql = "SELECT COUNT(DISTINCT DATE(created_at)) as days 
                FROM user_actions WHERE user_id = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->bind_param("i", $userId);
        $stmt->execute();
        $result = $stmt->get_result();
        $row = $result->fetch_assoc();
        return $row['days'] >= $requiredDays;
    }
    /**
     * 检查积分
     */
    private function checkPoints($userId, $requiredPoints) {
        $sql = "SELECT points FROM user_points WHERE user_id = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->bind_param("i", $userId);
        $stmt->execute();
        $result = $stmt->get_result();
        $row = $result->fetch_assoc();
        return $row && $row['points'] >= $requiredPoints;
    }
    /**
     * 检查用户等级
     */
    private function checkUserLevel($userId, $requiredLevel) {
        $sql = "SELECT level FROM user_levels WHERE user_id = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->bind_param("i", $userId);
        $stmt->execute();
        $result = $stmt->get_result();
        $row = $result->fetch_assoc();
        return $row && $row['level'] >= $requiredLevel;
    }
    /**
     * 清除用户缓存
     */
    private function clearUserCache($userId) {
        $this->cache->delete("user_badges_{$userId}");
        $this->cache->delete("user_action_count_{$userId}_*");
    }
    /**
     * 通知用户获得勋章
     */
    private function notifyUser($userId, $badgeId) {
        // 发送通知(邮件、短信、站内消息等)
        $badge = $this->getBadgeById($badgeId);
        $message = "恭喜你获得了【{$badge['name']}】勋章!";
        // 这里可以实现通知逻辑
        NotificationHelper::send($userId, $message);
    }
}

事件触发器

<?php
class BadgeEventTrigger {
    private $badgeManager;
    public function __construct($db) {
        $this->badgeManager = new BadgeManager($db);
    }
    /**
     * 用户完成某个操作时触发
     */
    public function onAction($userId, $actionType, $actionData = null) {
        // 记录操作日志
        $this->logAction($userId, $actionType, $actionData);
        // 检查勋章
        $awarded = $this->badgeManager->checkAndAward($userId, $actionType);
        // 返回新获得的勋章
        return $awarded;
    }
    /**
     * 用户注册时
     */
    public function onRegister($userId) {
        // 用户注册奖励
        $this->logAction($userId, 'register', []);
        return $this->badgeManager->checkAndAward($userId, 'register');
    }
    /**
     * 用户每日签到
     */
    public function onDailyCheckin($userId) {
        $this->logAction($userId, 'daily_checkin', []);
        return $this->badgeManager->checkAndAward($userId, 'daily_checkin');
    }
    /**
     * 用户完成任务
     */
    public function onTaskComplete($userId, $taskId) {
        $this->logAction($userId, 'task_complete', ['task_id' => $taskId]);
        return $this->badgeManager->checkAndAward($userId, 'task_complete');
    }
    /**
     * 记录用户操作
     */
    private function logAction($userId, $actionType, $actionData) {
        $sql = "INSERT INTO user_actions (user_id, action_type, action_data) 
                VALUES (?, ?, ?)";
        $stmt = $this->db->prepare($sql);
        $data = json_encode($actionData);
        $stmt->bind_param("iss", $userId, $actionType, $data);
        $stmt->execute();
    }
}

勋章配置示例

// 勋章配置示例
$badgeConfigs = [
    [
        'name' => '新手勋章',
        'code' => 'newbie',
        'description' => '注册成为新用户',
        'conditions' => [
            ['type' => 'action_count', 'action_type' => 'register', 'value' => 1]
        ]
    ],
    [
        'name' => '签到达人',
        'code' => 'checkin_master',
        'description' => '连续签到7天',
        'conditions' => [
            ['type' => 'continuous_days', 'value' => 7]
        ]
    ],
    [
        'name' => '活跃分子',
        'code' => 'active_member',
        'description' => '累计活跃30天',
        'conditions' => [
            ['type' => 'total_days', 'value' => 30]
        ]
    ],
    [
        'name' => '积分高手',
        'code' => 'points_master',
        'description' => '积分达到1000分',
        'conditions' => [
            ['type' => 'points', 'value' => 1000]
        ]
    ],
    [
        'name' => '任务达人',
        'code' => 'task_master',
        'description' => '完成10个任务',
        'conditions' => [
            ['type' => 'action_count', 'action_type' => 'task_complete', 'value' => 10]
        ]
    ],
    [
        'name' => '魅力之星',
        'code' => 'popular',
        'description' => '成功邀请5位好友',
        'conditions' => [
            ['type' => 'invite_count', 'value' => 5]
        ]
    ]
];

使用示例

// 初始化
$db = new mysqli('localhost', 'username', 'password', 'database');
$trigger = new BadgeEventTrigger($db);
// 用户注册时
$userId = 123;
$newBadges = $trigger->onRegister($userId);
// 用户完成操作时
$newBadges = $trigger->onAction($userId, 'post_create', ['content' => '...']);
// 每日签到
$newBadges = $trigger->onDailyCheckin($userId);
// 完成任务
$newBadges = $trigger->onTaskComplete($userId, 456);
// 手动检查和发放(定时任务)
$badgeManager = new BadgeManager($db);
$allUsers = $badgeManager->getAllActiveUsers();
foreach ($allUsers as $user) {
    $badgeManager->checkAndAward($user['id']);
}

扩展功能

// 添加定时检查任务
$schedule = new Schedule([
    'daily' => function() {
        // 每天凌晨执行
        $badgeManager = new BadgeManager($db);
        // 检查特殊勋章
        $badgeManager->checkSpecialBadge();
    },
    'hourly' => function() {
        // 每小时执行
        $badgeManager->checkTimeBasedBadges();
    }
]);
// 添加通知功能
class BadgeNotification {
    public static function send($userId, $badgeName) {
        // 站内信
        Message::create($userId, "获得新勋章:$badgeName");
        // 推送通知(可选)
        PushNotification::send($userId, "恭喜获得 $badgeName 勋章!");
    }
}

这个系统设计包含:

  • 灵活的勋章条件配置
  • 自动发放和手动检查
  • 缓存优化性能
  • 用户通知功能
  • 可扩展的事件触发机制

您可以根据具体需求调整条件类型和发放逻辑。

抱歉,评论功能暂时关闭!