数据库设计
要求:
每个用户可以签到7天,连续签到7天或者中途断签都重新开始计算签到天数,签到会获取对应奖励
分析:
1、连续签到
2、签到7天或者断签重新开始计算天数
3、签到获取奖励
设计:
1、每个用户可以连续签到,这就需要一个字段来记录连续签到天数
2、因为有连续签到7天或者断签重新开始计算的需求,所以需要一个字段来记录签到时间,来判断是否是连续签到从而改变连续签到天数,签到时判断表里的签到时间与现在的时间差是否为1天,为1天则连续签到,天数+1,反之则为断签,天数重置为1
3、签到获取奖励,需要记录签到天数对应的奖励(签到奖励表)
实现:
1、创建签到表(sign_in)
CREATE TABLE `sign_in` (
`id` int(11) NOT NULL COMMENT '主键',
`userId` int(11) NULL DEFAULT NULL COMMENT '用户id',
`num` int(11) NULL DEFAULT NULL COMMENT '签到天数',
`signTime` datetime(0) NULL DEFAULT NULL COMMENT '签到时间',
PRIMARY KEY (`id`)
);
2、创建奖励表(sign_in_reward)
CREATE TABLE `sign_in_reward` (
`id` int(11) NOT NULL COMMENT '主键',
`coin` int(11) NOT NULL COMMENT '金币',
PRIMARY KEY (`id`)
);
3、用户表
CREATE TABLE `user` (
`id` int(11) NOT NULL COMMENT '主键',
`userId` int(11) NOT NULL COMMENT '用户id',
`coin` int(11) NOT NULL COMMENT '金币',
PRIMARY KEY (`id`)
);
签到:
/**
* @api {post} /minwx/sign/signIn 签到
* @apiName signIn
* @apiParam {string} userId 用户id
* @apiGroup 签到
*/
public function signIn()
{
try {
$userId = $this->request->param('userId');
$signIn = new ModelSignIn();
$res = $signIn->get(['userId' => $userId]);
// 判断用户是否签到过
if ($res) {
// 更新用户数据
if ($this->diffBetweenTwoDays(date('Y-m-d', time()), substr($res['signTime'], 0, 10)) == 1) {
// 连续签到,更新签到时间,签到天数+1
$num = $res['num'] + 1;
} else {
// 没有连续签到,更新签到时间,签到次数初始化为1
$num = 1;
}
$signIn->where(['userId' => $userId])->update(['signTime' => date('Y-m-d H:i:s', time()), 'num' => $num]);
} else {
// 添加用户数据
$signIn->data([
'userId' => $this->request->param('userId'),
'num' => 1,
'signTime' => date('Y-m-d H:i:s', time())
]);
$signIn->save();
}
// 获取签到奖励
$reward = Db::table('sign_in_reward')->where(['id'=> $num % 7 == 0 ? 7 : $num % 7])->find();
// 给予用户奖励
$user = new User();
$userInfo = $user->where(['userId' => $userId])->setInc('coin', $reward['coin']);
return json(['code'=>1,'msg'=>'签到成功','data'=>'']);
} catch (Exception $e) {
return json(['code'=>-1,'msg'=>'系统错误','err'=>$e->getMessage()]);
}
}
//两个日期之间相差的天数
public function diffBetweenTwoDays($day1, $day2)
{
$second1 = strtotime($day1);
$second2 = strtotime($day2);
if ($second1 < $second2) {
$tmp = $second2;
$second2 = $second1;
$second1 = $tmp;
}
return ($second1 - $second2) / 86400;
}
获取签到:
/**
* @api {post} /minwx/sign/getSignIn 获取签到
* @apiName getSignIn
* @apiParam {string} userId 用户id
* @apiGroup 签到
*/
public function getSignIn()
{
Db::startTrans();
try {
$userId= $this->request->param('userId');
// 获取用户信息
$user = new User();
$userInfo = $user->get(['userId' => $userId]);
// 获取签到日期
$signIn = new ModelSignIn();
$arr = $signIn->get(['userId' => $userId]);
// 判断是否签到过
if ($arr) {
// 计算天数
$differDay = $this->diffBetweenTwoDays(date('Y-m-d', time()), substr($arr['signTime'], 0, 10));
// 0今日签到,1昨日已签到
if ($differDay == 0 || $differDay == 1) {
// 这里不对数据库的签到天数做处理,可以一直记录连续签到的天数,方便后面需求的拓展
// 而在逻辑上连续签到7天需重置签到天数,所以对签到天数做7求余(具体天数看实际项目需求更改求余),得出逻辑需求里的连续签到天数
$num = $arr['num'] % 7 == 0 ? 7 : $arr['num'] % 7;
} else {
// 断签,重置签到天数,因为是获取签到而不是签到,所以num重置为0
$num = 0;
$signIn->where(['userId' => $userId])->update(['num' => $num]);
}
// 判断今日是否签到
if ($differDay == 0) {
// 今天已签到
$today = 1;
} else {
// 今日未签到
$today = 0;
}
} else {
// 未签到,插入数据,签到天数为0
$num = 0;
$today = 0;
$signIn->where(['userId' => $userId])->update(['num' => $num]);
}
// 获取签到奖励
$reward = Db::table('sign_in_reward')->order('id')->select();
$res = [
'coin' => $userInfo['coin'], // 用户金币
'signIn' => $num, // 签到天数
'reward' => $reward, // 签到奖励
'today' => $today // 今天是否签到(0没有、1有)
];
Db::commit();
return json(['code'=>1,'msg'=>'获取成功','data'=>$res]);
} catch (Exception $e) {
Db::rollback();
return json(['code'=>-1,'msg'=>'系统错误','err'=>$e->getMessage()]);
}
}