打卡活动设计

打卡活动设计_第1张图片
打卡活动设计_第2张图片在这里插入图片描述
打卡活动设计_第3张图片一、数据库

CREATE TABLE `yq_clock_setting` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`title` VARCHAR(255) NULL DEFAULT NULL COMMENT '标题' COLLATE 'utf8mb4_general_ci',
	`deposit` DECIMAL(10,2) NULL DEFAULT '0.00' COMMENT '押金',
	`days` INT(11) NOT NULL DEFAULT '0' COMMENT '挑战天数',
	`maxpeople` INT(11) NOT NULL DEFAULT '0' COMMENT '最大参与人数0不限制',
	`clock_start_time` TIME NULL DEFAULT NULL COMMENT '打卡开始时间',
	`clock_end_time` TIME NULL DEFAULT NULL COMMENT '打卡结束时间',
	`create_time` INT(11) NULL DEFAULT NULL COMMENT '创建时间',
	PRIMARY KEY (`id`) USING BTREE
)
COMMENT='打卡配置'
COLLATE='utf8mb4_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=4
;
CREATE TABLE `yq_clock_take` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`user_id` INT(11) NOT NULL DEFAULT '0',
	`deposit` DECIMAL(10,2) NOT NULL DEFAULT '0.00' COMMENT '押金',
	`getmoney` DECIMAL(10,2) NOT NULL DEFAULT '0.00' COMMENT '瓜分金额(不包括押金)',
	`days` INT(11) NOT NULL DEFAULT '0' COMMENT '挑战天数',
	`clock_start_time` TIME NULL DEFAULT NULL COMMENT '打卡开始时间',
	`clock_end_time` TIME NULL DEFAULT NULL COMMENT '打卡结束时间',
	`status` TINYINT(4) NOT NULL DEFAULT '0' COMMENT '-1挑战失败0刚参与1挑战中2挑战成功',
	`create_time` INT(11) NULL DEFAULT NULL COMMENT '参与时间',
	PRIMARY KEY (`id`) USING BTREE
)
COMMENT='打开活动参与纪录\r\n'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=157
;
CREATE TABLE `yq_clock_take_log` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`user_id` INT(11) NOT NULL DEFAULT '0' COMMENT '打卡人',
	`take_id` INT(11) NOT NULL DEFAULT '0' COMMENT '参与ID',
	`clock_time` INT(11) NULL DEFAULT NULL COMMENT '打卡时间',
	PRIMARY KEY (`id`) USING BTREE,
	INDEX `take_id` (`take_id`) USING BTREE
)
COMMENT='打卡记录'
COLLATE='utf8mb4_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=113
;

二、控制器




namespace app\api\controller;

use app\common\services\ClockService;
use itholiday\enum\ClockTakeStatus;
use think\Db;

/**
 * 打卡
 * Class Clock
 * @package app\api\controller
 */
class Clock extends Apibase
{
    protected $noNeedLogin = ['info', 'notice', 'lastresult'];

    /**
     * 打卡配置-我的参与情况
     */
    public function info()
    {
        $data['button_status'] = 0;//0立即参与、1立即打卡、2距下次打卡、3等待开奖
        $data['button_remain'] = 0;
        $data['button_msg'] = '立即参与';
        //是否参与过
        $flag = db('clock_take')->alias('A')->join('__CLOCK_SETTING__ B', 'A.days=B.days')->field('A.*,B.title')->where('A.user_id', $this->user_id)->order('A.id', 'desc')->find();
        if (!empty($flag)) {
            if ($flag['status'] == ClockTakeStatus::$take) {
                $data['button_status'] = 1;//0立即参与、1立即打卡、2距下次打卡、3等待开奖
                $data['button_remain'] = 0;
                $data['button_msg'] = '立即打卡';
                $create_tomorrow_start_time = strtotime('+1 day', strtotime(date('Y-m-d', $flag['create_time']) . ' ' . $flag['clock_start_time']));
                if ($create_tomorrow_start_time > time()) {
                    $data['button_status'] = 2;//0立即参与、1立即打卡、2距下次打卡、3等待开奖
                    $data['button_remain'] = $create_tomorrow_start_time - time();
                    $data['button_msg'] = '距下次打卡还有' . $data['button_remain'] . '秒';
                }
            } else if ($flag['status'] == ClockTakeStatus::$loading) {
                $data['button_status'] = 2;//0立即参与、1立即打卡、2距下次打卡、3等待开奖
                $data['button_remain'] = 0;
                $data['button_msg'] = '距下次打卡';
                //有正在进行中的,可能挑战完了还未开奖
                $docounts = db('clock_take_log')->where('user_id', $this->user_id)->where('take_id', $flag['id'])->count();
                $today_clock_end_time = strtotime(date('Y-m-d') . ' ' . $flag['clock_end_time']);
                /*if ($docounts >= $flag['days'] && $today_clock_end_time > time()) {
                    //完成
                    $data['button_status'] = 3;//0立即参与、1立即打卡、2距下次打卡、3等待开奖
                    $data['button_remain'] = $today_clock_end_time - time();
                    $data['button_msg'] = '等待' . $data['button_remain'] . '秒后开奖';
                } else {
                    //挑战失败
                    $time = date('H:i:s');

                    if ($time < $flag['clock_start_time']) {
                        $data['button_status'] = 2;//0立即参与、1立即打卡、2距下次打卡、3等待开奖
                        $create_today_start_time = strtotime(date('Y-m-d') . ' ' . $flag['clock_start_time']);
                        $data['button_remain'] = $create_today_start_time - time();
                        $data['button_msg'] = '距下次打卡还有' . $data['button_remain'] . '秒';
                    }
                }*/
                //  判断打卡次数与需要打卡的天数相比较,如果打卡天数
                if ($docounts >= $flag['days']) {
                    //  已经打完卡 判断是否到开奖时间
                    if($today_clock_end_time > time()){
                        //  未到开奖时间
                        $data['button_status'] = 3;//0立即参与、1立即打卡、2距下次打卡、3等待开奖
                        $data['button_remain'] = $today_clock_end_time - time();
                        $data['button_msg'] = '等待' . $data['button_remain'] . '秒后开奖';
                    }else{
                        //  到开奖时间
                        $data['button_status'] = 0;//0立即参与、1立即打卡、2距下次打卡、3等待开奖
                        $data['button_remain'] = 0;
                        $data['button_msg'] = '立即参与';
                    }
                }elseif ($docounts < $flag['days']) {
                    $clock_time = db('clock_take_log')->where('user_id', $this->user_id)->where('take_id', $flag['id'])->order('clock_time desc')->value("clock_time");
                    $create_tomorrow_start_time = strtotime('+1 day', strtotime(date('Y-m-d', $clock_time) . ' ' . $flag['clock_start_time']));
                    //  未到打卡时间  获取距离下次打卡时间
                    $data['button_status'] = 2;//0立即参与、1立即打卡、2距下次打卡、3等待开奖
                    $data['button_remain'] = $create_tomorrow_start_time - time();
                    $data['button_msg'] = '距下次打卡还有' . $data['button_remain'] . '秒';
                }
            }
        }
        $data['button_remain'] = sectotime($data['button_remain']);

        //打卡配置
        $clocklist = db('clock_setting')->group('days')->order('days', 'asc')->select();
        if (empty($clocklist)) $this->resultdata(['0', '打卡活动未开放.请在后台配置']);
        $data['clocklist'] = $clocklist ?: [];
        $today_start_time = mktime(0, 0, 0, date('m'), date('d'), date('Y'));
        foreach ($data['clocklist'] as &$item) {
            //本期参与
            $item['nowqishu'] = date('Ymd');
            $nowcanyu = db('clock_take')->where('days', $item['days'])->whereBetweenTime('create_time', $today_start_time, time())->count();
            $item['nowcanyu'] = $nowcanyu ?: 0;
            //瓜分金额
            $guafen = db('clock_take')->where('days', $item['days'])->whereTime('create_time', 'today')->sum('deposit');
            $item['guafen'] = intval($guafen ?: 0);
        }
        //打卡记录参与纪录
        $data['takelist'] = ClockService::clocktakenotice();
        //活动规则
        $clock_setting = cmf_get_option('clock_setting');
        $data['config'] = $clock_setting;
        if(!empty($data['config']['rules'])){
            $data['config']['rules'] = htmlspecialchars_decode($data['config']['rules']);
        }

        $this->resultdata(['1', 'ok'], $data);
    }

    public function info2()
    {
        $data['button_status'] = 0;//0立即参与、1立即打卡、2距下次打卡、3等待开奖
        $data['button_remain'] = 0;
        $data['button_msg'] = '立即参与';
        //是否参与过
        $flag = db('clock_take')->alias('A')->join('__CLOCK_SETTING__ B', 'A.days=B.days')->field('A.*,B.title')->where('A.user_id', $this->user_id)->order('A.id', 'desc')->find();
        if (!empty($flag)) {
            if ($flag['status'] == ClockTakeStatus::$take) {
                $data['button_status'] = 1;//0立即参与、1立即打卡、2距下次打卡、3等待开奖
                $data['button_remain'] = 0;
                $data['button_msg'] = '立即打卡';
                $create_tomorrow_start_time = strtotime('+1 day', strtotime(date('Y-m-d', $flag['create_time']) . ' ' . $flag['clock_start_time']));
                if ($create_tomorrow_start_time > time()) {
                    $data['button_status'] = 2;//0立即参与、1立即打卡、2距下次打卡、3等待开奖
                    $data['button_remain'] = $create_tomorrow_start_time - time();
                    $data['button_msg'] = '距下次打卡还有' . $data['button_remain'] . '秒';
                }
            } else if ($flag['status'] == ClockTakeStatus::$loading) {
                $data['button_status'] = 1;//0立即参与、1立即打卡、2距下次打卡、3等待开奖
                $data['button_remain'] = 0;
                $data['button_msg'] = '立即打卡';
                //有正在进行中的,可能挑战完了还未开奖
                $docounts = db('clock_take_log')->where('user_id', $this->user_id)->where('take_id', $flag['id'])->count();
                $today_clock_end_time = strtotime(date('Y-m-d') . ' ' . $flag['clock_end_time']);
                if ($docounts >= $flag['days'] && $today_clock_end_time > time()) {
                    //完成
                    $data['button_status'] = 3;//0立即参与、1立即打卡、2距下次打卡、3等待开奖
                    $data['button_remain'] = $today_clock_end_time - time();
                    $data['button_msg'] = '等待' . $data['button_remain'] . '秒后开奖';
                } else {
                    //挑战失败
                    $time = date('H:i:s');
                    if ($time < $flag['clock_start_time']) {
                        $data['button_status'] = 2;//0立即参与、1立即打卡、2距下次打卡、3等待开奖
                        $create_today_start_time = strtotime(date('Y-m-d') . ' ' . $flag['clock_start_time']);
                        $data['button_remain'] = $create_today_start_time - time();
                        $data['button_msg'] = '距下次打卡还有' . $data['button_remain'] . '秒';
                    }
                }
            }
        }
        $data['button_remain'] = sectotime($data['button_remain']);

        //打卡配置
        $clocklist = db('clock_setting')->group('days')->order('days', 'asc')->select();
        if (empty($clocklist)) $this->resultdata(['0', '打卡活动未开放.请在后台配置']);
        $data['clocklist'] = $clocklist ?: [];
        $today_start_time = mktime(0, 0, 0, date('m'), date('d'), date('Y'));
        foreach ($data['clocklist'] as &$item) {
            //本期参与
            $item['nowqishu'] = date('Ymd');
            $nowcanyu = db('clock_take')->where('days', $item['days'])->whereBetweenTime('create_time', $today_start_time, time())->count();
            $item['nowcanyu'] = $nowcanyu ?: 0;
            //瓜分金额
            $guafen = db('clock_take')->whereTime('create_time', 'today')->where('days', $item['days'])->sum('deposit');
            $item['guafen'] = intval($guafen ?: 0);
        }
        //打卡记录参与纪录
        $data['takelist'] = ClockService::clocktakenotice();
        //活动规则
        $clock_setting = cmf_get_option('clock_setting');
        $data['config'] = $clock_setting;
        $this->resultdata(['1', 'ok'], $data);
    }

    /**
     * 上期结果
     */
    public function lastresult()
    {
        $days = input('days');
        if ($days < 1) $this->resultdata(['0', '参数错误']);
        //上期结果
        $today_start_time = mktime(0, 0, 0, date('m'), date('d'), date('Y'));
        $clock_qi_start_time = $today_start_time - $days * 86400;
        $clock_qi_end_time = $today_start_time - ($days - 1) * 86400;
        $lastresult = Db::query("select count(*) as canyu,sum(deposit) as guafen from yq_clock_take where `days`={$days} and create_time between {$clock_qi_start_time} and {$clock_qi_end_time}");
        $data['canyu'] = $lastresult ? ($lastresult[0]['canyu'] ?? 0) : 0;
        //瓜分20200520
//        $data['guafen'] = intval($lastresult ? ($lastresult[0]['guafen'] ?? 0) : 0);
//        $data['guafen'] = 0;
        //汇报率20200520
        $hblist = Db::query("select (getmoney+deposit)/deposit as huibao from yq_clock_take where `days`={$days} and getmoney>0 and (create_time between {$clock_qi_start_time} and {$clock_qi_end_time})");
//        $hblist = Db::query("select (getmoney)/deposit as huibao from yq_clock_take where `days`={$days} and getmoney>0 and (create_time between {$clock_qi_start_time} and {$clock_qi_end_time})");
        if (empty($hblist)) {
            $data['huibao'] = '0';
        } else {
            $sum = 0;
            foreach ($hblist as $item) {
                $sum += $item['huibao'];
            }
            $data['huibao'] = $sum / count($hblist) * 100;
        }
        //上期幸运榜20200520
        /*$list = db('clock_take')->alias('a')->join('__USER__ b', 'a.user_id=b.id')
            ->field('a.status,a.getmoney,b.wx_nickname,b.nickname,b.mobile,b.avatar,b.headimgurl')
            ->where('a.days', $days)
            ->whereBetweenTime('a.create_time', $clock_qi_start_time, $clock_qi_end_time)
            ->where('a.status', ClockTakeStatus::$done)
            ->where('a.getmoney', 'gt', 0)
            ->order('a.id', 'desc')->limit(5)->select();*/
        $list = db('clock_take')->field('id,user_id,status,getmoney')->whereBetweenTime('create_time', $clock_qi_start_time, $clock_qi_end_time)->where('status', 2)->where('getmoney', 'gt', 0)->order('id', 'desc')->select();
        $luckylist = [];
        $data['guafen'] = 0;
        if (!empty($list)) {
            foreach ($list as &$item) {
                $userinfo = db("user")->where("id", $item['user_id'])->find();
                $item['wx_nickname'] = $userinfo['wx_nickname'];
                $item['nickname'] = $userinfo['nickname'];
                $item['mobile'] = $userinfo['mobile'];
                $item['avatar'] = $userinfo['avatar'];
                $item['headimgurl'] = $userinfo['headimgurl'];
                $avatar = $item['avatar'] ?: $item['headimgurl'] ?: '/static/images/avatar.png';
                $nickname = $item['nickname'] ?: $item['wx_nickname'] ?: substr_replace($item['mobile'], '****', 3, 4);
                array_push($luckylist, ['avatar' => $avatar, 'nickname' => $nickname, 'getmoney' => round($item['getmoney'], 2)]);
                $data['guafen'] += $item['getmoney'];
            }
        }
        $data['luckylist'] = $luckylist ?: [];
        $this->resultdata(['1', 'ok'], $data);
    }

    /**
     * 参与打卡活动-打卡
     */
    public function take()
    {
        $days = input('days', 0, 'intval');
        if (empty($days)) $this->resultdata(['0', '参数错误']);
        $clock = db('clock_setting')->where('days', $days)->group('days')->field('title,deposit,days,maxpeople,clock_start_time,clock_end_time')->find();
        if (empty($clock)) $this->resultdata(['0', '没有这样的挑战']);
        //是否参与过
        $flag = db('clock_take')->alias('A')->join('__CLOCK_SETTING__ B', 'A.days=B.days')->field('A.*,B.title')
            ->where('A.user_id', $this->user_id)->where('A.status', 'in', [ClockTakeStatus::$take, ClockTakeStatus::$loading])->order('A.id', 'desc')->find();
        if (empty($flag)) {
            //没有正在进行中的挑战,可以直接参与
            //参与人数限制、参与、提示下次时间准时打卡
            if ($clock['maxpeople'] > 0) {
                $all = db('clock_take')->where('days', $days)->where('status', ClockTakeStatus::$take)->whereTime('create_time', 'today')->count();
                $all >= $clock['maxpeople'] && $this->resultdata(['0', '参与人数封顶,请参与其他类型或明天再来']);
            }
            if ($clock['deposit'] > $this->user['user_money']) {
                $this->resultdata(['0', '余额不足']);
            }
            $res = ClockService::takepartin($clock, $this->user_id);
            if ($res) {
//                $this->resultdata(['1', '参与成功,请明天' . $clock['clock_start_time'] . '到' . $clock['clock_end_time'] . '准时打卡']);
                $this->resultdata(['1', '参与成功,请明天' . $clock['clock_start_time'] . '到' . $clock['clock_end_time'] . '准时打卡,打卡周期 '.$days.' 天']);
            } else {
                $this->resultdata(['0', '参与失败,请稍后后重试']);
            }
        } else {
            if ($days != $flag['days']) {
                $this->resultdata(['0', '您已参与了' . $flag['days'] . '天' . $flag['title']]);
            }

            //php获取昨日起始时间戳和结束时间戳
            $last_take_log = db('clock_take_log')->where('take_id', $flag['id'])->order('id', 'desc')->find();
            if (empty($last_take_log)) {
                //隔两天去打卡
                if (date('Y-m-d', $flag['create_time']) != date('Y-m-d')) {
                    $takeday_clock_end_time = strtotime(date('Y-m-d', $flag['create_time']) . ' ' . $flag['clock_end_time']);
                    if ($takeday_clock_end_time + 86400 < time()) {
                        ClockService::clocktakefail($flag, $clock);
                        $this->resultdata(['0', '挑战失败,请参与下期']);
                    }
                }
            } else {
                //隔两天去打卡
                $takelogday_clock_end_time = strtotime(date('Y-m-d', $last_take_log['clock_time']) . ' ' . $flag['clock_end_time']);
                if ($takelogday_clock_end_time + 86400 < time()) {
                    ClockService::clocktakefail($flag, $clock);
                    $this->resultdata(['0', '挑战失败,请参与下期']);
                }
            }
            //必须是连续两天打卡的逻辑
            if ($flag['status'] == ClockTakeStatus::$take) {
                //挑战失败
                $create_today_start_time = strtotime(date('Y-m-d', $flag['create_time']) . ' ' . $flag['clock_start_time']) + 86400;
                if (time() < $create_today_start_time) {
                    $this->resultdata(['0', '还未到打卡时间']);
                }
                //TODO 直接打卡、。是否结束打卡并颁奖
                $res = db('clock_take_log')->insertGetId([
                    'user_id' => $this->user_id,
                    'take_id' => $flag['id'],
                    'clock_time' => time()
                ]);
                if ($res) {
                    db('clock_take')->where('id', $flag['id'])->setField('status', ClockTakeStatus::$loading);
                    //未完成
                    $this->resultdata(['1', '打卡成功,已打卡1次']);
                } else {
                    $this->resultdata(['0', '打卡失败,请稍后重试']);
                }
            } else {
                //有正在进行中的,可能挑战完了还未开奖
                $docounts = db('clock_take_log')->where('user_id', $this->user_id)->where('take_id', $flag['id'])->count();
                if ($docounts >= $flag['days']) {
                    //完成
                    $this->resultdata(['1', '您已完成' . $flag['days'] . '天挑战,等待' . $flag['clock_end_time'] . '开奖']);
                } else {
                    $time = date('H:i:s');
                    if ($time < $flag['clock_start_time']) {
                        $this->resultdata(['0', '还未到打卡时间']);
                    }
                    //未完成
                    //TODO 直接打卡、。是否结束打卡并颁奖
                    $res = db('clock_take_log')->insertGetId([
                        'user_id' => $this->user_id,
                        'take_id' => $flag['id'],
                        'clock_time' => time()
                    ]);
                    if ($res) {
                        if ($docounts + 1 >= $flag['days']) {
                            //完成
                            $this->resultdata(['1', '您已完成' . $flag['days'] . '天' . $clock['title'] . ',等待' . $flag['clock_end_time'] . '开奖']);
                        } else {
                            //未完成
                            $this->resultdata(['1', '打卡成功,已连续打卡' . ($docounts + 1) . '次']);
                        }
                    } else {
                        $this->resultdata(['0', '打卡失败,请稍后重试']);
                    }
                }
            }
        }
    }

    public function take2()
    {
        $days = input('days', 0, 'intval');
        if (empty($days)) $this->resultdata(['0', '参数错误']);
        $clock = db('clock_setting')->where('days', $days)->group('days')->field('title,deposit,days,maxpeople,clock_start_time,clock_end_time')->find();
        if (empty($clock)) $this->resultdata(['0', '没有这样的挑战']);
        //是否参与过
        $flag = db('clock_take')->alias('A')->join('__CLOCK_SETTING__ B', 'A.days=B.days')->field('A.*,B.title')
            ->where('A.user_id', $this->user_id)->where('A.status', 'in', [ClockTakeStatus::$take, ClockTakeStatus::$loading])->order('A.id', 'desc')->find();
        if (empty($flag)) {
            //没有正在进行中的挑战,可以直接参与
            //参与人数限制、参与、提示下次时间准时打卡
            if ($clock['maxpeople'] > 0) {
                $all = db('clock_take')->where('days', $days)->where('status', ClockTakeStatus::$take)->whereTime('create_time', 'today')->count();
                $all >= $clock['maxpeople'] && $this->resultdata(['0', '参与人数封顶,请参与其他类型或明天再来']);
            }
            if ($clock['deposit'] > $this->user['user_money']) {
                $this->resultdata(['0', '余额不足']);
            }
            $res = ClockService::takepartin($clock, $this->user_id);
            if ($res) {
//                $this->resultdata(['1', '参与成功,请明天' . $clock['clock_start_time'] . '到' . $clock['clock_end_time'] . '准时打卡']);
                $this->resultdata(['1', '参与成功,请明天' . $clock['clock_start_time'] . '到' . $clock['clock_end_time'] . '准时打卡,打卡周期 '.$days.' 天']);
            } else {
                $this->resultdata(['0', '参与失败,请稍后后重试']);
            }
        } else {
            if ($days != $flag['days']) {
                $this->resultdata(['0', '您已参与了' . $flag['days'] . '天' . $flag['title']]);
            }
            //php获取昨日起始时间戳和结束时间戳
            $last_take_log = db('clock_take_log')->where('take_id', $flag['id'])->order('id', 'desc')->find();
            if (empty($last_take_log)) {
                //隔两天去打卡
                if (date('Y-m-d', $flag['create_time']) != date('Y-m-d')) {
                    $takeday_clock_end_time = strtotime(date('Y-m-d', $flag['create_time']) . ' ' . $flag['clock_end_time']);
                    if ($takeday_clock_end_time + 86400 < time()) {
                        ClockService::clocktakefail($flag, $clock);
                        $this->resultdata(['0', '挑战失败,请参与下期']);
                    }
                }
            } else {
                //隔两天去打卡
                $takelogday_clock_end_time = strtotime(date('Y-m-d', $last_take_log['clock_time']) . ' ' . $flag['clock_end_time']);
                if ($takelogday_clock_end_time + 86400 < time()) {
                    ClockService::clocktakefail($flag, $clock);
                    $this->resultdata(['0', '挑战失败,请参与下期']);
                }
            }
            //必须是连续两天打卡的逻辑
            if ($flag['status'] == ClockTakeStatus::$take) {
                //挑战失败
                $create_today_start_time = strtotime(date('Y-m-d', $flag['create_time']) . ' ' . $flag['clock_start_time']) + 86400;
                if (time() < $create_today_start_time) {
                    $this->resultdata(['0', '还未到打卡时间']);
                }
                //TODO 直接打卡、。是否结束打卡并颁奖
                $res = db('clock_take_log')->insertGetId([
                    'user_id' => $this->user_id,
                    'take_id' => $flag['id'],
                    'clock_time' => time()
                ]);
                if ($res) {
                    db('clock_take')->where('id', $flag['id'])->setField('status', ClockTakeStatus::$loading);
                    //未完成
                    $this->resultdata(['1', '打卡成功,已打卡1次']);
                } else {
                    $this->resultdata(['0', '打卡失败,请稍后重试']);
                }
            } else {
                //有正在进行中的,可能挑战完了还未开奖
                $docounts = db('clock_take_log')->where('user_id', $this->user_id)->where('take_id', $flag['id'])->count();
                if ($docounts >= $flag['days']) {
                    //完成
                    $this->resultdata(['1', '您已完成' . $flag['days'] . '天挑战,等待' . $flag['clock_end_time'] . '开奖']);
                } else {
                    $time = date('H:i:s');
                    if ($time < $flag['clock_start_time']) {
                        $this->resultdata(['0', '还未到打卡时间']);
                    }
                    //未完成
                    //TODO 直接打卡、。是否结束打卡并颁奖
                    $res = db('clock_take_log')->insertGetId([
                        'user_id' => $this->user_id,
                        'take_id' => $flag['id'],
                        'clock_time' => time()
                    ]);
                    if ($res) {
                        if ($docounts + 1 >= $flag['days']) {
                            //完成
                            $this->resultdata(['1', '您已完成' . $flag['days'] . '天' . $clock['title'] . ',等待' . $flag['clock_end_time'] . '开奖']);
                        } else {
                            //未完成
                            $this->resultdata(['1', '打卡成功,已连续打卡' . ($docounts + 1) . '次']);
                        }
                    } else {
                        $this->resultdata(['0', '打卡失败,请稍后重试']);
                    }
                }
            }
        }
    }

    /**
     * 我的挑战统计
     */
    public function my()
    {
        $canyu = db('clock_take')->where('user_id', $this->user_id)->count();
        $success = db('clock_take')->where('user_id', $this->user_id)->where('status', ClockTakeStatus::$done)->count();
        $guafen = db('clock_take')->where('user_id', $this->user_id)->sum('getmoney');
        $data['canyu'] = $canyu ?: 0;
        $data['success'] = $success ?: 0;
        $data['guafen'] = $guafen ?: 0;
        $this->resultdata(['1', 'ok'], $data);
    }

    /**
     * 我的打卡挑战记录
     * TODO 开完奖后 status改为1
     */
    public function clocklist()
    {
        //参与日期 天数1/3 进行中(未完成、完成) 瓜分金额(待开奖)
        $list = db('clock_take')->where('user_id', $this->user_id)->field('id,create_time,days,status,deposit,getmoney')->order('id', 'desc')->select();
        if (!empty($list)) {
            foreach ($list as &$item) {
                $item['create_time'] = date('Ymd', $item['create_time']);
                $hasdone = db('clock_take_log')->where('user_id', $this->user_id)->where('take_id', $item['id'])->count();
                $item['hasdone'] = $hasdone ?: 0;
                $item['getmoney'] = ($item['days'] <= $hasdone) && ($item['status'] == ClockTakeStatus::$loading) ? '待开奖' : round($item['getmoney'], 2);
                if ($item['status'] == ClockTakeStatus::$fail) {
                    $item['status'] = '失败';
                    $item['getmoney'] = '0.00';
                } else if ($item['status'] == ClockTakeStatus::$done) {
                    $item['status'] = '已完成';
                    $item['getmoney'] = round($item['getmoney'], 2) ?: '进行中';
                } else {
                    $item['status'] = '进行中';
                    $item['getmoney'] = '进行中';
                }
            }
        }
        $this->resultdata(['1', 'ok'], $list ?: []);
    }
}

三、核心代码



namespace app\common\services;

use app\adminer\model\sLog;
use itholiday\enum\ClockTakeStatus;
use itholiday\enum\UserMoneyLogEnum;
use itholiday\util\LoggerUtil;
use itholiday\util\RedisUtil;
use think\Db;

/**
 * 打卡逻辑
 * Class ClockService
 * @package app\common\services
 */
class ClockService
{

    /**
     * 参与打卡
     * @param $clock
     * @param $user_id
     * @return bool
     */
    public static function takepartin($clock, $user_id)
    {
        Db::startTrans();
        try {
            $user = db('user')->find($user_id);
            //写记录
            $res = db('clock_take')->insertGetId([
                'user_id' => $user_id,
                'status' => ClockTakeStatus::$take,
                'deposit' => $clock['deposit'],
                'getmoney' => 0,
                'days' => $clock['days'],
                'clock_start_time' => $clock['clock_start_time'],
                'clock_end_time' => $clock['clock_end_time'],
                'create_time' => time(),
            ]);
            if (!$res) throw new \Exception('');
            // 扣押金并写日志
            $res = db('user')->where('id', $user_id)->setDec('user_money', $clock['deposit']);
            if (!$res) throw new \Exception('');
            $res = db('user_money_log')->insertGetId([
                'user_id' => $user_id,
                'coin' => 0 - $clock['deposit'],
                'user_money' => $user['user_money'] - $clock['deposit'],
                'log_type' => UserMoneyLogEnum::$take_clock,
                'notes' => '参与' . $clock['days'] . '日' . $clock['title'],
                'title' => $clock['days'] . '日' . $clock['title'],
                'create_time' => time(),
            ]);
            if (!$res) throw new \Exception('');
        } catch (\Exception $e) {
            Db::rollback();
            return false;
        }
        Db::commit();
        return true;
    }

    public static function clocktakenotice()
    {
        $list = db('clock_take')->alias('a')->join('__USER__ b', 'a.user_id=b.id')
            ->field('a.days,b.wx_nickname,b.nickname,b.mobile,b.avatar,b.headimgurl')->where('a.status', ClockTakeStatus::$take)->order('a.id', 'desc')->limit(5)->select();
        $takelist = [];
        if (!empty($list)) {
            foreach ($list as $item) {
                $avatar = $item['avatar'] ?: $item['headimgurl'] ?: '/static/images/avatar.png';
                $nickname = $item['nickname'] ?: $item['wx_nickname'] ?: substr_replace($item['mobile'], '****', 3, 4);
                $desipot = db("clock_setting")->where("days", $item['days'])->value("deposit");
                $newFileds = $item['days'].'日挑战';
                array_push($takelist, ['avatar' => $avatar, 'nickname' => $nickname, 'days' => $desipot,'days_field'=>$newFileds]);
                //  array_push($takelist, ['avatar' => $avatar, 'nickname' => $nickname, 'days' => $item['days']]);
            }
        }
        return $takelist;
    }

    /**
     * 挑战成功
     * @param $clocktake
     */
    public static function clocktakesuccess($clocktake, $clock)
    {
        $log['uid'] = $clocktake['user_id'];
        $log['content'] = json_encode(array('title' => '您已完成' . $clocktake['days'] . '天' . $clock['title'], 'content' => ''));
        $log['status'] = 0;//有弹窗
        $log['create_time'] = time();
        db('window')->insert($log);
        db('clock_take')->where('id', $clocktake['id'])->setField('status', ClockTakeStatus::$done);
        return true;
    }

    /**
     * 挑战失败
     * @param $clocktake
     */
    public static function clocktakefail($clocktake, $clock = array())
    {
        $log['uid'] = $clocktake['user_id'];
        $log['content'] = json_encode(['title' => '您未坚持,' . $clock['days'] . '日' . $clock['title'] . '失败', 'content' => '']);
        $log['status'] = 0;//有弹窗
        $log['create_time'] = time();
        db('window')->insert($log);
        db('clock_take')->where('id', $clocktake['id'])->setField('status', ClockTakeStatus::$fail);
        return true;
    }

    public static function clockRedisQueueSuccess($clock_loading_set_item)
    {
        //标记处理完成
        RedisUtil::getInstance()->sRem('clock_loading', $clock_loading_set_item);//移除集合
        if (empty(RedisUtil::getInstance()->sCard('clock_loading'))) {
            RedisUtil::getInstance()->set('clock_over', 1);//全部完成
            $endToday = mktime(0, 0, 0, date('m'), date('d') + 1, date('Y')) - 1;
            RedisUtil::getInstance()->setExpire('clock_over', $endToday - time());//到今天结束
        }
    }

    /**
     * 打卡发奖
     */
    public static function publishreward()
    {
        //2020-05-15性能优化 会重复查询处理=》只处理一次
        $clock_over = RedisUtil::getInstance()->get('clock_over');//今日打卡业务是否处理完成
        if ($clock_over) return;//处理完成
        $sCard = RedisUtil::getInstance()->sCard('clock_loading');
        if (empty($sCard)) {
            //没有成员,今日第一次进入,初始化处理集合。
            $clock_setting = unserialize(RedisUtil::getInstance()->get('clock_setting'));
            if (empty($clock_setting)) {
                echo '请在后台配置打卡' . PHP_EOL;
                return;
            }
            foreach ($clock_setting as $item) {
                RedisUtil::getInstance()->sAdd('clock_loading', serialize($item));//写入集合
            }
        }

        //取出待处理的业务项目
        $clock_loadings = RedisUtil::getInstance()->sMembers('clock_loading');
        if (empty($clock_loadings)) return;
        dump($clock_loadings);
        $time = date('H:i:s');
        foreach ($clock_loadings as $item) {
            $item = unserialize($item);
            if ($time < $item['clock_end_time']) continue;//没到结束打卡时间
            self::doClockJob($item);
        }
    }

    public static function doClockJob($data)
    {
        $clock_loading_set_item = serialize($data);//集合元素
        $days = $data['days'] ?? 0;
        if (empty($days)) return true;
        $clock = db('clock_setting')->where('days', $days)->find();
        $today_start_time = mktime(0, 0, 0, date('m'), date('d'), date('Y'));
        $clock_qi_start_time = $today_start_time - $days * 86400;
        $clock_qi_end_time = $today_start_time - ($days - 1) * 86400;
        $takelist = db('clock_take')->where('days', $clock['days'])->whereBetweenTime('create_time', $clock_qi_start_time, $clock_qi_end_time)->select();//上一期参与的
        if (empty($takelist)) {
            //  标记处理完成
            ClockService::clockRedisQueueSuccess($clock_loading_set_item);
            return true;
        }

        LoggerUtil::logger('$takelist:' . json_encode($takelist, JSON_UNESCAPED_UNICODE), 'clock_publish_queue');
        try {
            $finishNum = 0;//完成人数
            $finishUidinfos = [];//完成UID
            $reward_pool = 0;
            foreach ($takelist as $item) {
                //判断此人是否完成
                $doneCount = db('clock_take_log')->where('take_id', $item['id'])->count();
                if ($doneCount < $item['days']) {
                    $reward_pool += $item['deposit'];//添加奖金池
                    //挑战失败
                    ClockService::clocktakefail($item, $clock);
                } else {
                    $finishNum++;
                    array_push($finishUidinfos, $item);
                    //挑战完成
                    ClockService::clocktakesuccess($item, $clock);
                    //对完成的退回押金
                    db('user')->where('id', $item['user_id'])->setInc('user_money', $item['deposit']);
                    sLog::userMoneyLog($item['user_id'], $item['deposit'], UserMoneyLogEnum::$done_clock, '完成' . $item['days'] . '天' . $clock['title'] . ',退回押金' . $item['deposit'] . '元', '打卡退回押金');
                }
            }
            file_put_contents('clocklog.txt', '$finishNum:' . $finishNum . PHP_EOL, FILE_APPEND);
            file_put_contents('clocklog.txt', '$reward_pool:' . $reward_pool . PHP_EOL, FILE_APPEND);
            file_put_contents('clocklog.txt', '$finishUidinfos:' . json_encode($finishUidinfos) . PHP_EOL, FILE_APPEND);
            //对完成的瓜分
            if ($finishNum && $reward_pool >= 0.01 * $finishNum) {
                //瓜分多余的 算法:注册时间距现在时间越短、积极参与的获得的概率大
                $r = get_red($reward_pool, $finishNum, 1);
                foreach ($finishUidinfos as $k => $item) {
                    $getmoney = $r[$k] / 100;//将最终结果,转换成元为单位
                    file_put_contents('clocklog.txt', '$getmoney:' . $getmoney . PHP_EOL, FILE_APPEND);
                    db('user')->where('id', $item['user_id'])->setInc('user_money', $getmoney);
                    db('user')->where('id', $item['user_id'])->setInc('add_money', $getmoney);
                    sLog::userMoneyLog($item['user_id'], $getmoney, UserMoneyLogEnum::$done_clock, '完成' . $item['days'] . '天' . $clock['title'] . ',瓜分到奖金' . $getmoney . '元', '打卡瓜分奖金');
                    db('clock_take')->where('id', $item['id'])->setField('getmoney', $getmoney);
                }
            }
            //标记处理完成
            ClockService::clockRedisQueueSuccess($clock_loading_set_item);
        } catch (\Exception $e) {
            LoggerUtil::logger('exception:' . $e->getMessage() . PHP_EOL . '消息数据为:' . json_encode($data, JSON_UNESCAPED_UNICODE), 'clock_publish_queue');
            return false;
        }
        return true;
    }
}

你可能感兴趣的:(php)