PHP实现签到功能(带补签和连续签到天数)

作者: 乘风御上者 分类: PHP 发布时间: 2019-12-11 16:01

项目中需要添加签到的功能,要求有连续天数和能补签。一开始没注意,等到写代码的时候才发现补签还是需要点算法的。

# //签到用到的表结构
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]);

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!

发表回复