PHP实现签到功能(带补签和连续签到天数)
项目中需要添加签到的功能,要求有连续天数和能补签。一开始没注意,等到写代码的时候才发现补签还是需要点算法的。
# //签到用到的表结构
CREATE TABLE `signin` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID',
`successions` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '连续签到天数',
`type` enum('normal','fillup') DEFAULT 'normal' COMMENT '签到类型',
`createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='签到表';
其中连续签到天数很好解决,只要在签到前查一下表,看看昨天是否有数据,有则在昨天数据基础上+1(successions + 1),否则直接等于1。
补签功能则需要一点逻辑计算:
$userId = '补签人ID';
// 补签日期
$time = strtotime('2019-12-01');
// 找到补签日期的前一天的数据
$prev = Signin::where('user_id', $userId)
->whereTime('createtime', 'between', [date("Y-m-d", strtotime("-1 day", $time)), date("Y-m-d 23:59:59", strtotime("-1 day", $time))])
->find();
// 前一天存在则取其连续天数 + 1
if ($prev) {
$successions = $prev['successions'] + 1;
}
// 把补签日期之后所有签到数据取出并按照签到时间正序
$nextList = Signin::where('user_id', $userId)
->where('createtime', '>=', strtotime("+1 day", $time))
->order('createtime', 'asc')
->select();
// 遍历签到之后的所有签到日期,检测签到日期是否连续,连续的更新连续天数
foreach ($nextList as $index => $item) {
// 排除补签之后最近的一天后,若后面的某天连续天数是1,则说明期间有断签,后面的无需再走
if ($index > 0 && $item['successions'] == 1) {
break;
}
// 假设距离补签之后的第几天
$day = $index + 1;
// 根据补签日期计算出之后每天签到的日期,与实际的签到日期对比,一致则说明是连续签到
if (date("Y-m-d", $item['createtime']) == date("Y-m-d", strtotime("+{$day} day", $time))) {
$item->successions = $successions + $day;
$item->save();
}
}
// 43200无实际意义,因为$time是2019-12-01 00:00:00比较敏感,随意指定一天中的某个时间而已。
Signin::create(['user_id' => $userId, 'type' => 'fillup', 'successions' => $successions, 'createtime' => $time + 43200]);