redis = Redis::instance(); //parent::_initialize(); } public function test(){ //$ur = new UserRecentlyRead(); //$ur->getOneReadRecord('U1B11000000039'); //$res = $ur->getRecentlyRead(1); //$pp = $this->redis->hgetall('U1B11000000029'); //dump($pp); // $thismodel = new UserRecentlyRead(); // $read = $thismodel->getRecentlyRead(); // dump($read);die; $book_id = 11000000039; //echo $this->redis->get('hello');die; //$chapters = model('Book')::getChapterList($book_id); $bookinfo = model('Book')->bookinfo($book_id); dump($bookinfo);die; // echo "
";
//        print_r($chapters);
        echo(microtime());
        $res = $this->bookfee(3,$bookinfo,'测试章节1',142,196511666,1);
        dump($res);
        echo(microtime());
    }

    /**
     * 点击下一章
     * @param $userId  $this->user->id; 如果没有userid 就写到cookie里(最多5本)
     * @param $bookId  url上传的
     * @param $chapter_id   url上带的chapter_id ,cookie里的chaper_id 和 sid 优先级低(高于)
     * @param $chapter_name
     * @param $idx 第几章
     * @param int $kandian config('site.book_chapter_price')
     * @return array  $returnArr['type'] = 4; // type:1扣书币成功 2.书币不足,3扣书币失败,4缺少参数,5获取书籍信息失败,6未登录,7,游客到了计费章节  $returnArr['isRecharge']=1,扣费,返回数组里没有isRecharge这个参数是免费的
     * @throws \Exception
     */
    public function bookfee($admin_id,$book,$chapter_name,$idx,$chapter_id,$user){
        $freeChapter = config('site.book_free_chapter_num'); //全局免费章节数
        if(intval($book['free_chapter_num'])>0){  //如果本书籍设置了免费章节数,以本书籍的免费章节数为准
            $freeChapter = $book['free_chapter_num'];
        }
        //维护书阅读数量
        $bookNumKey = 'B-N';
        $this->redis->hincrby($bookNumKey, $book['id'], 1);

        $bookKey = 'B:'.$book['id'];
        if($this->redis->exists($bookKey)){ //判断有没有这个key
            $this->redis->hincrby($bookKey,'read_num',1);
        }

        $kandian = config('site.book_chapter_price'); //全局每章节书币数
        $returnArr = [];
        if(!$book || !$admin_id || !$chapter_id || !$chapter_name || !$idx){  //必传参数
            $returnArr['error'] = 1;
            $returnArr['type'] = 4;
            $returnArr['msg'] = '缺少参数';
            return $returnArr;
        }

        if(!empty($user)) {
            $userId = $user['id'];
        }else{
            $userId = null;
        }


        if(Config::get("site.free")==1){ //容灾处理,如果计费出现问题在后台配置read_free=true则所有书籍都免费
            $this->recentlyRead($chapter_name,$chapter_id,$book,$userId); //记录最近阅读
            $returnArr['error'] = 0;
            $returnArr['type'] = 1;
            $returnArr['msg'] = '免费章节';
            return $returnArr;
        }

        if(intval($book['free_stime'])time()){  //此书设置了免费时长并且当前时间在免费时长内则免费阅读
            $this->recentlyRead($chapter_name,$chapter_id,$book,$userId); //记录最近阅读
            $returnArr['error'] = 0;
            $returnArr['type'] = 1;
            $returnArr['msg'] = '免费章节';
            return $returnArr;
        }

        if($idx > $freeChapter && empty($userId)){
            $returnArr['error'] = 1;
            $returnArr['type'] = 7;
            $returnArr['isRecharge'] = 1;
            $returnArr['msg'] = '游客到了计费章节';
            return $returnArr;
        }

        if($idx<=$freeChapter && empty($userId)){ //记录游客最近阅读
            $this->recentlyRead($chapter_name,$chapter_id,$book);
            $returnArr['error'] = 0;
            $returnArr['type'] = 1;
            $returnArr['msg'] = '免费章节';
            return $returnArr;
        }

        $bookId = $book['id'];  //书籍id

        $consumeDB = model('Consume')->setConnect($userId);

        $book = model('Book')->bookinfo($bookId);  //获取书籍信息
        if(!$book){
            $returnArr['error'] = 1;
            $returnArr['type'] = 5;
            $returnArr['msg'] = '获取书籍信息失败';
            return $returnArr;
        }


        $insertData = [];
        $insertData['user_id'] = $userId;
        $insertData['book_id'] = $bookId;
        $insertData['chapter_id'] = $chapter_id;
        $insertData['chapter_name'] = $chapter_name;
        $insertData['createtime'] = time();
        $insertData['updatetime'] = time();

        $insertConsume = [];  //计费

        if($idx<=$freeChapter){ //免费章节
            $this->recentlyRead($chapter_name,$chapter_id,$book,$userId); //记录最近阅读
            $returnArr['error'] = 0;
            $returnArr['type'] = 1;
            $returnArr['msg'] = '免费章节';
            return $returnArr;
        }else{
            $returnArr['isRecharge'] = 1;
        }

        if($user['vip_endtime']>time()){  //vip用户,全部章节免费
            $this->recentlyRead($chapter_name,$chapter_id,$book,$userId); //记录最近阅读
            $returnArr['error'] = 0;
            $returnArr['type'] = 1;
            $returnArr['msg'] = '免费章节';
            return $returnArr;
        }

        //判断该本书是按本收费还是按章收费,是否自定义每章的价格
        $billing_type = $book['billing_type'];
        $price = $book['price'];
        $insertConsume['type'] = 1;
        $caseWhere = ['user_id'=>$userId,'book_id'=>$bookId,'type'=>1,'chapter_id'=>$chapter_id];
        if($billing_type == 2 && intval($price)>0){ //按本收费
            $chapter_id = null;
            $kandian = intval($price);
            $insertConsume['type'] = 2;
            $caseWhere = ['user_id'=>$userId,'book_id'=>$bookId,'type'=>2];
        }

        if($billing_type == 1 && intval($price)>0){ //自定义每章价格
            $kandian = intval($price);
        }

        //以下处理扣费章节
        $isConsume = $consumeDB->where($caseWhere)->find();
        if(!empty($isConsume)){
            $this->recentlyRead($chapter_name,$chapter_id,$book,$userId); //记录最近阅读
            $returnArr['error'] = 0;
            $returnArr['type'] = 1;
            $returnArr['msg'] = '已经付过费';
            return $returnArr;
        }

        //未扣费处理
        $fee = [];
        $feeBook = [];
        $feeBook['spending_count_kandian'] = $kandian;
        $feeBook['spending_recharge_kandian'] = 0;
        //书币是否够用
        $total_free_kandian = model('Recharge')->getTotalFreeKandian($userId);
        if($total_free_kandian + $user['kandian'] < $kandian){
            $returnArr['error'] = 1; // 0:成功,1:失败
            $returnArr['type'] = 2; // type:1扣书币成功 2.书币不足,3扣书币失败,4缺少参数
            $returnArr['msg'] = '抱歉,您的书币不足';  //提示信息
            return $returnArr;
        }

        if($total_free_kandian>=$kandian){
            $fee['free_kandian'] = $total_free_kandian-$kandian;
            $feeBook['spending_free_kandian'] = $kandian;
        }else{
            $fee['free_kandian'] = 0;
            $fee['kandian'] = $user['kandian']+$total_free_kandian-$kandian;
            $feeBook['spending_free_kandian'] = $total_free_kandian;
            $feeBook['spending_recharge_kandian'] = $kandian-$total_free_kandian;
        }

        if(isset($fee['kandian']) && $fee['kandian'] != $user['kandian']){
            $userRes = model('user')->setConnect($userId)->update($fee,['id'=>$userId]);  //减少用户书币
            if(!$userRes){
                $returnArr['error'] = 1;
                $returnArr['type'] = 3;
                $returnArr['msg'] = '抱歉,操作失败';
                return $returnArr;
            }
            //更新redis
            $userKey = 'UN:'.$userId;
            if($this->redis->exists($userKey)){
                $this->redis->hmset($userKey,$fee);
                //up by wanghy 0407 用户信息过期时间由24小时修改为10小时
                $this->redis->expire($userKey, 36000);
            }
        }

        $this->recentlyRead($chapter_name,$chapter_id,$book,$userId); //记录最近阅读

        //减少免费书币
        if($total_free_kandian > 0){
            $rid = model('Recharge')->getLastFreeRecord($userId);
            model('Recharge')->reduceFreeKandian($userId,$kandian,$rid);
        }
        //user表操作结束,以下处理consume表和user_recently_read表
        $beginToday=mktime(0,0,0,date('m'),date('d'),date('Y'));

        //判断此用户今天有没有在这本书扣过费,放入缓存
        $everyDayKey = 'HC:'.$userId.':'.$bookId.':'.date("d");
        $isConsumeToday = false;
        if($this->redis->exists($everyDayKey)){
            $isConsumeToday = true;
        }else{
            $consumeToday = $consumeDB->where(['user_id'=>$userId,'book_id'=>$bookId])->order('id','desc')->find();
            if(isset($consumeToday['updatetime']) && $consumeToday['updatetime'] > $beginToday){
                $this->redis->setex($everyDayKey,86400,'1');
                $isConsumeToday = true;
            }
        }
        $insertConsume['user_id'] = $userId;
        $insertConsume['book_id'] = $bookId;
        $insertConsume['book_name'] = $book['name'];
        $insertConsume['chapter_id'] = $chapter_id;
        $insertConsume['chapter_name'] = $chapter_name;
        $insertConsume['kandian'] = $feeBook['spending_recharge_kandian'];
        $insertConsume['free_kandian'] = $feeBook['spending_free_kandian'];
        $insertConsume['createtime'] = time();
        $insertConsume['updatetime'] = time();
        $insertConsume['extend1'] = $bookId;
        $insertConsume['extend2'] = $chapter_id;
        //插入消费记录
        $consumeDB->insert($insertConsume);

        $feeBook['type'] = 1;
        $feeBookAll['type'] = 1;
        $feeBook['book_id'] = $bookId;
        $feeBookAll['book_id'] = $bookId;
        $feeBook['updatetime'] = time();
        $feeBookAll['updatetime'] = time();
        $feeBookAll['admin_id'] = 0;

        //0408 去掉用户喜好字段维护
        //记录用户喜好类目
//        if(!empty($user)){
//            $keyUBC = 'U-BC:' . $userId;
//            if ($this->redis->exists($keyUBC)) {
//                $user_cateIds = $this->redis->get($keyUBC);
//                if (!$user_cateIds) {
//                    $user_cateIds = '';
//                }
//            } else {
//                $user_cateIds = $user['book_category_ids'];
//            }
//            $category_id = $book['book_category_id'];
//            $categoryString = '';
//            if (!empty($user_cateIds)) {
//                $categorys = explode(',', $user_cateIds);
//                if (!in_array($category_id, $categorys)) {
//                    if (count($categorys) > 4) {
//                        unset($categorys[0]);
//                        foreach ($categorys as $key => $val) {
//                            $categoryString .= $val . ',';
//                        }
//                        $categoryString .= $category_id;
//                    } else {
//                        $categoryString = $user_cateIds . ',' . $category_id;
//                    }
//                } else {
//                    $categoryString = $user_cateIds;
//                }
//            } else {
//                $categoryString = $category_id;
//            }
//            $this->redis->setex($keyUBC, 86400, $categoryString);
//        }


        //管理员数据汇总
        $this->bookConsumeCollect(0,$bookId,$isConsumeToday,$feeBook['spending_count_kandian'],$feeBook['spending_free_kandian'],$feeBook['spending_recharge_kandian']);
        //分销商,代理商插入小说汇总统计记录
        $this->bookConsumeCollect($admin_id,$bookId,$isConsumeToday,$feeBook['spending_count_kandian'],$feeBook['spending_free_kandian'],$feeBook['spending_recharge_kandian']);

        $returnArr['error'] = 0;
        $returnArr['type'] = 1;
        $returnArr['msg'] = '扣书币成功';
        return $returnArr;
    }

    /**
     * 书籍计费统计
     * @param $channel_id
     * @param $book_id
     * @param $isConsumeToday
     * @param $count_kandian
     * @param $free_kandian
     * @param $recharge_kandian
     * @throws \Exception
     */
    private function bookConsumeCollect($channel_id,$book_id,$isConsumeToday,$count_kandian,$free_kandian,$recharge_kandian){
        //设置渠道籍列表
        $collect_list_key = "BC-CL:".date("Ymd");
        $this->redis->sadd($collect_list_key,$channel_id);
        $this->redis->expire($collect_list_key,86400*2);
        //设置渠道商书籍列表
        $collect_channel_book_key = "BC-BL:{$channel_id}:".date("Ymd");
        $this->redis->sadd($collect_channel_book_key,$book_id);
        $this->redis->expire($collect_channel_book_key,86400*2);
        //设置渠道商对应书籍数据
        $collect_key =  "BC:{$book_id}:{$channel_id}:".date("Ymd");
        if($data = json_decode($this->redis->get($collect_key),true)){
            if(!$isConsumeToday){
                $data['spending_users'] = intval($data['spending_users'] ?? 0)+1;
            }
            $data['spending_num'] = intval($data['spending_num'] ?? 0)+1;
            $data['spending_count_kandian'] = intval($data['spending_count_kandian'] ?? 0)+$count_kandian;
            $data['spending_free_kandian'] = intval($data['spending_free_kandian'] ?? 0)+$free_kandian;
            $data['spending_recharge_kandian'] = intval($data['spending_recharge_kandian'] ?? 0)+$recharge_kandian;
            $this->redis->setex($collect_key,86400*2,json_encode($data));
        }else{
            $data['spending_users'] = 1;
            $data['spending_num'] = 1;
            $data['spending_count_kandian'] = $count_kandian;
            $data['spending_free_kandian'] = $free_kandian;
            $data['spending_recharge_kandian'] = $recharge_kandian;
            $this->redis->setex($collect_key,86400*2,json_encode($data));
        }

    }


    /**
     * 最近阅读
     * @param $chapter_name
     * @param $chapter_id
     * @param $book  array
     * @param null $userId
     * @return bool
     */
    public function recentlyRead($chapter_name,$chapter_id,$book,$userId=null){
        //记录最近阅读
        if(!$chapter_name || !$chapter_id || !$book){
            return false;
        }
        $bookId = $book['id'];
        $key = 'U-R:'.$userId;  //最近阅读记录zset结构
        $hkey = 'U-B:'.$userId.':'.$bookId; //最近阅读阅读记录每条的数据:hash结构

        $RencentlyReadDB = model('UserRecentlyRead');
        $RencentlyReadDB = $RencentlyReadDB->setConnect($userId);

        if(empty($userId)){ //游客
            $chapterinfo = [];
            $chapterinfo['id'] = $chapter_id;
            $chapterinfo['name'] = $chapter_name;
            $RencentlyReadDB->recentCookie($book['id'], $chapterinfo); //阅读记录记入cookie 只记录5条数据
            return true;
        }

        $chapterInfo = [];
        $chapterInfo['id'] = $chapter_id;
        $chapterInfo['name'] = $chapter_name;

        $bookInfo = [];
        $bookInfo['image'] = $book['image'];
        $bookInfo['book_name'] = $book['name'];
        $bookInfo['last_chapter_name'] = $book['last_chapter_name'];
        $bookInfo['last_chapter_utime'] = $book['last_chapter_utime'];
        $bookInfo['state'] = $book['state'];

        $insertData = [];
        $insertData['user_id'] = $userId;
        $insertData['book_id'] = $bookId;
        $insertData['chapter_id'] = $chapter_id;
        $insertData['chapter_name'] = $chapter_name;
        $insertData['createtime'] = time();
        $insertData['updatetime'] = time();

        if(!$this->redis->exists($key)){ //如果redis里最近阅读记录为空拉取一下最近阅读记录(防灾)
            $RencentlyReadDB->getRecentlyRead(0, 10);
        }
        //判断redis里有没有记录
        $userRead = null;
        if($this->redis->exists($hkey) && $this->redis->exists($key)){
            $userRead = $this->redis->hgetall($hkey);
        }
        //如果redis里没有记录判断数据库里有没有记录
        if(empty($userRead)){
            $userRead = $RencentlyReadDB->where(['user_id'=>$userId,'book_id'=>$bookId])->find(); //是否阅读过此书
        }

        if (!empty($userRead)) { //更新
            $getId = $userRead['id'];
            $RencentlyReadDB->where(['id'=>$getId])->update(['chapter_id' => $chapter_id, 'updatetime' => time(),'chapter_name'=>$chapter_name,'flag'=>1]);

            if($getId){
                $insertData['id'] = $getId;
                $updateArr = array_merge($insertData,$bookInfo);
                $this->redis->hmset($hkey, $updateArr);
                if($this->redis->exists($key)) {
                    $this->redis->zrem($key, $hkey);
                }
                $this->redis->zadd($key, $updateArr['updatetime'], $hkey);
                $this->redis->expire($key,43200);  //设置失效时间
                $this->redis->expire($hkey,43200);  //设置失效时间
            }
        } else {
            $RencentlyReadDB->insert($insertData);
            $id = $RencentlyReadDB->getLastInsID();
            $insertData['id'] = $id;
            $insertArr = array_merge($insertData, $bookInfo);
            $this->redis->hmset($hkey, $insertArr);
            $this->redis->expire($hkey,43200);  //设置失效时间
            if($this->redis->exists($key)){
                $this->redis->zrem($key, $hkey);
            }
            if(!$this->redis->exists($key)){ //(如果redis里最近阅读记录为空拉取一下最近阅读记录防灾)
                $RencentlyReadDB->getRecentlyRead(time()+1, 10);
            }
            $this->redis->zadd($key, $insertArr['updatetime'], $hkey);
            $this->redis->expire($key,43200);  //设置失效时间
        }

    }
}