本文目录导读:

我来详细介绍PHP项目实现用户签到积分的完整方案。
数据库设计
签到记录表
CREATE TABLE `user_sign_in` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '用户ID',
`sign_date` date NOT NULL COMMENT '签到日期',
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '签到时间',
`points` int(11) DEFAULT 0 COMMENT '获得积分',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_date` (`user_id`, `sign_date`),
KEY `idx_user_id` (`user_id`),
KEY `idx_sign_date` (`sign_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
用户积分表
CREATE TABLE `user_points` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`total_points` int(11) DEFAULT 0 COMMENT '总积分',
`continuous_days` int(11) DEFAULT 0 COMMENT '连续签到天数',
`last_sign_date` date DEFAULT NULL COMMENT '最后签到日期',
`updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
积分记录表(可选,用于记录明细)
CREATE TABLE `points_log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`type` tinyint(4) DEFAULT 0 COMMENT '类型:1签到,2消费,3兑换',
`points` int(11) NOT NULL COMMENT '变动积分',
`description` varchar(255) DEFAULT NULL COMMENT '描述',
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
PHP核心代码实现
签到类设计
<?php
class SignInSystem {
private $db;
private $userId;
public function __construct($db, $userId) {
$this->db = $db;
$this->userId = $userId;
}
/**
* 用户签到
*/
public function signIn() {
try {
$this->db->beginTransaction();
$today = date('Y-m-d');
// 检查今天是否已签到
if ($this->isTodaySigned()) {
return ['success' => false, 'message' => '今天已签到'];
}
// 获取签到状态
$status = $this->getSignInStatus();
$continuousDays = $status['continuous_days'];
$lastSignDate = $status['last_sign_date'];
// 计算连续签到天数
$yesterday = date('Y-m-d', strtotime('-1 day'));
if ($lastSignDate == $yesterday) {
$continuousDays++;
} else {
$continuousDays = 1;
}
// 计算本次签到积分
$points = $this->calculatePoints($continuousDays);
// 记录签到
$this->recordSignIn($today, $points);
// 更新用户积分状态
$this->updateUserPoints($points, $continuousDays, $today);
// 记录积分变动
$this->logPointsChange($points, "第{$continuousDays}天签到");
$this->db->commit();
return [
'success' => true,
'points' => $points,
'continuous_days' => $continuousDays,
'message' => "签到成功,获得{$points}积分"
];
} catch (Exception $e) {
$this->db->rollBack();
return ['success' => false, 'message' => '签到失败'];
}
}
/**
* 检查今天是否已签到
*/
private function isTodaySigned() {
$today = date('Y-m-d');
$stmt = $this->db->prepare(
"SELECT id FROM user_sign_in
WHERE user_id = ? AND sign_date = ?"
);
$stmt->execute([$this->userId, $today]);
return $stmt->fetch() ? true : false;
}
/**
* 获取签到状态
*/
private function getSignInStatus() {
$stmt = $this->db->prepare(
"SELECT continuous_days, last_sign_date
FROM user_points WHERE user_id = ?"
);
$stmt->execute([$this->userId]);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$result) {
return ['continuous_days' => 0, 'last_sign_date' => null];
}
return $result;
}
/**
* 计算签到积分
* 采用递增策略:连续签到天数越多,积分越多
*/
private function calculatePoints($continuousDays) {
// 基础积分
$basePoints = 1;
// 连续签到加成
$bonus = 0;
if ($continuousDays >= 7) {
$bonus = 7; // 连续7天额外7分
} elseif ($continuousDays >= 5) {
$bonus = 5;
} elseif ($continuousDays >= 3) {
$bonus = 3;
}
return $basePoints + $bonus;
}
/**
* 记录签到
*/
private function recordSignIn($date, $points) {
$stmt = $this->db->prepare(
"INSERT INTO user_sign_in (user_id, sign_date, points)
VALUES (?, ?, ?)"
);
$stmt->execute([$this->userId, $date, $points]);
}
/**
* 更新用户积分
*/
private function updateUserPoints($points, $continuousDays, $date) {
// 检查用户积分记录是否存在
$stmt = $this->db->prepare(
"SELECT id FROM user_points WHERE user_id = ?"
);
$stmt->execute([$this->userId]);
if ($stmt->fetch()) {
// 更新
$stmt = $this->db->prepare(
"UPDATE user_points
SET total_points = total_points + ?,
continuous_days = ?,
last_sign_date = ?,
updated_at = NOW()
WHERE user_id = ?"
);
$stmt->execute([$points, $continuousDays, $date, $this->userId]);
} else {
// 插入新记录
$stmt = $this->db->prepare(
"INSERT INTO user_points (user_id, total_points, continuous_days, last_sign_date)
VALUES (?, ?, ?, ?)"
);
$stmt->execute([$this->userId, $points, $continuousDays, $date]);
}
}
/**
* 记录积分变动
*/
private function logPointsChange($points, $description) {
$stmt = $this->db->prepare(
"INSERT INTO points_log (user_id, type, points, description, created_at)
VALUES (?, 1, ?, ?, NOW())"
);
$stmt->execute([$this->userId, $points, $description]);
}
/**
* 获取用户签到记录
*/
public function getSignInRecords($limit = 30) {
$stmt = $this->db->prepare(
"SELECT sign_date, points, created_at
FROM user_sign_in
WHERE user_id = ?
ORDER BY sign_date DESC
LIMIT ?"
);
$stmt->execute([$this->userId, $limit]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 获取用户当前签到状态
*/
public function getCurrentStatus() {
$stmt = $this->db->prepare(
"SELECT total_points, continuous_days, last_sign_date
FROM user_points WHERE user_id = ?"
);
$stmt->execute([$this->userId]);
$status = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$status) {
return [
'total_points' => 0,
'continuous_days' => 0,
'last_sign_date' => null,
'can_sign_in' => true
];
}
// 是否可以签到
$today = date('Y-m-d');
$status['can_sign_in'] = ($status['last_sign_date'] != $today);
return $status;
}
}
前端调用示例
// sign_in.php
<?php
require_once 'config/database.php';
require_once 'class/SignInSystem.php';
// 获取用户ID(实际应从session获取)
$userId = $_SESSION['user_id'] ?? 0;
if ($_POST['action'] == 'sign_in') {
$signIn = new SignInSystem($db, $userId);
$result = $signIn->signIn();
echo json_encode($result);
exit;
}
// 获取签到状态
$signIn = new SignInSystem($db, $userId);
$status = $signIn->getCurrentStatus();
$records = $signIn->getSignInRecords();
?>
积分规则建议
基础规则
- 每日签到:1分
- 连续3天:额外3分
- 连续5天:额外5分
- 连续7天:额外7分
高级规则(可选)
- 每月全勤:额外奖励50分
- 断签后重新计算连续天数
- 特殊节日双倍积分
注意事项
- 防止刷分:限制IP/设备频繁签到
- 数据一致性:使用事务保证签到和积分更新原子性
- 缓存优化:使用Redis缓存今日签到状态
- 定时任务:每月重置或统计签到数据
这个实现包含了完整的签到积分功能,可以根据业务需求调整积分计算规则。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播