項目功能迭代系列之簽到功能的實現

一、功能背景

繼續上一篇文章項目功能迭代之排行榜查詢功能的實現之後,考慮到圈子用戶曬精美的早餐圖的資源比較少,但是又想參加公司組織的圈子打卡活動,所以產品提出需要增加圈子簽到的功能。

規則:用戶簽到以圈子爲單位,每個用戶在單個圈子每天只能簽到一次,簽到之後會獲得相應的虛擬茄子幣獎勵,簽到成功之後會彈出相應的簽到信息以及虛擬茄子幣獎勵信息。

說明:打卡操作包括圖文打卡和簽到,在數據中的表現形式用action_type字段進行區分

流程:用戶簽到  -> 調用簽到接口 -> 請求賬號中心的茄子幣接口同步茄子幣 -> 請求成功後置灰簽到按鈕 -> 刷新當前頁面

二、相關表結構

用戶打卡信息表:記錄用戶的打卡信息

DROP TABLE IF EXISTS `qz_circle_detail`;
CREATE TABLE `qz_circle_detail` (
  `detail_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '內容 id',
  `detail_content` text CHARACTER SET utf8 NOT NULL COMMENT '詳細內容',
  `detail_title` varchar(255) CHARACTER SET utf8 NOT NULL DEFAULT 'NULL' COMMENT '標題',
  `add_time` int(11) NOT NULL DEFAULT '0' COMMENT '添加時間',
  `published_id` int(11) NOT NULL DEFAULT '0' COMMENT '發佈人 id',
  `view_count` int(11) NOT NULL DEFAULT '0' COMMENT '遊覽數',
  `current_count` int(11) NOT NULL DEFAULT '0' COMMENT '每日的遊覽數',
  `last_count_time` int(11) NOT NULL DEFAULT '0' COMMENT '最後一次統計的時間',
  `circle_id` int(11) NOT NULL DEFAULT '0' COMMENT '圈子 id',
  `sort` int(2) NOT NULL DEFAULT '0' COMMENT '排序字段',
  `comments` int(10) NOT NULL DEFAULT '0' COMMENT '評論數',
  `has_attach` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT 'NULL' COMMENT '上傳的文件( 目前是圖片)',
  `votes` int(10) DEFAULT '0',
  `action_type` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT 'punch' COMMENT '動作的類型,punch爲打卡,sign_in爲簽到',
  `is_recommend` tinyint(1) DEFAULT '0' COMMENT '是否爲精選,0爲否,1爲是',
  PRIMARY KEY (`detail_id`)
) ENGINE=InnoDB AUTO_INCREMENT=20383 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;

簽到數據記錄控制表:用戶控制每個用在每個圈子中籤到的記錄

DROP TABLE IF EXISTS `qz_integral_log`;
CREATE TABLE `qz_integral_log` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `uid` int(11) DEFAULT '0',
  `action` varchar(50) DEFAULT NULL,
  `integral` int(11) DEFAULT NULL,
  `note` varchar(128) DEFAULT NULL,
  `balance` int(11) DEFAULT '0',
  `item_id` int(11) DEFAULT '0',
  `time` int(10) DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `uid` (`uid`) USING BTREE,
  KEY `action` (`action`) USING BTREE,
  KEY `time` (`time`) USING BTREE,
  KEY `integral` (`integral`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=30183 DEFAULT CHARSET=utf8;

三、核心邏輯代碼

1、接口方法

/**
    * 用戶簽到
    */
   public function user_sign_in_action(){

      $circle_id = $_GET['circle_id'];
      $uid = $this->user_id;
      $show_sign_in_switch = 'no';
      //先判斷今天是否已經打卡了
      $punch_count = $this->model('circle')->judge_if_today_punched($uid,$circle_id);
      $target_gold = 0;

      $integral_log_data = array(
         'action' => 'CIRCLE_SIGN_IN',
         'notes' => '圈子簽到#'.$circle_id,
         'item_id' => $circle_id
      );
      //獲取當前打卡信息
      //直接獲取對應圈子的基本連續打卡信息
      $login_user = $this->model('circle')->get_user_circle_continuous_data($uid,$circle_id);
      $total_continuous_times = intval($login_user['total_contious_punch_times']);
      error_log('punch_count=======IS zero============');
      if($punch_count == 0){
         //沒有打卡則添加對應的打卡積分記錄
         $rule_key = 'sign_in';
         //返回打卡返回的茄子幣數目
         $target_gold = $this->model('circle')->add_user_gold(
             $uid,$circle_id,$rule_key,$integral_log_data,
             $this->get_account_center_user_info(),true
         );
         $show_sign_in_switch = 'yes';
      }else{
         $this->model('integral')->log(
             $uid, $integral_log_data['action'], 
             $target_gold, $integral_log_data['notes'], 
             $integral_log_data['item_id']
         );
         $current_month_punch_time = intval($login_user['current_month_punch_time'])+1;
         $login_user['total_contious_punch_times'] =  $total_continuous_times;
         $login_user['current_month_punch_time'] =  $current_month_punch_time;
      }

      $login_user['target_gold'] = $target_gold;
      //無論如何都要進行打卡數據的添加
      $time = date('m月d日',time());

      $title = '';
      $sign_data = array(
         'title' => $title,
         'content' => '',
         'action_type' => 'sign_in'
      );
      $detail_id = $this->model('circleDetail')->publish_circle_Detail(
          trim($sign_data['title']),$sign_data['content'],
          $circle_id,$uid,$sign_data['action_type']
       );

      //獲取當前打卡信息
      //直接獲取對應圈子的基本連續打卡信息
      $login_user = $this->model('circle')->get_user_circle_continuous_data($uid,$circle_id);
      $total_continuous_times = intval($login_user['total_contious_punch_times']);
      $current_month_punch_time = intval($login_user['current_month_punch_time']);
      $login_user['total_contious_punch_times'] =  $total_continuous_times;
      $login_user['current_month_punch_time'] =  $current_month_punch_time;
      $login_user['target_gold'] =  $target_gold;
      //
      $title = '完成'.$time.'簽到打卡,連續第'.$total_continuous_times.'天';
      $update_data = array(
         'detail_title' => $title
      );
      error_log('detail_id ===========>'.$detail_id);
      $this->model('circle')->update_circle_detail_by_id($update_data,$detail_id);


      $continuous_sign_in_action = 'CIRCLE_CONTINUOUS_SIGN_IN';
      $continuous_punch_action = 'CIRCLE_CONTINUOUS_PUNCH';
      $account_user_info = $this->get_account_center_user_info();
      //計算連續打卡天數
//    $this->model('circle')->process_circle_continuous_punch(
                $uid,$circle_id,$continuous_sign_in_action,$account_user_info
          );
      //計算連續天數
//    $this->model('circle')->process_circle_continuous_punch(
            $uid,$circle_id,$continuous_punch_action,$account_user_info
          );
      //返回數據
      $data = array(
         'user_info' => $login_user,
         'show_sign_in_switch' => $show_sign_in_switch
      );
      H::ajax_json_output(AWS_APP::RSM($data, 1, null));
   }

2、circle Model中的方法

/**
 * 判斷用戶當天是否已經打卡
 * @param unknown $circle_id
 * */
public function judge_if_today_punched($uid,$circle_id){
  $sql= "SELECT count(1) count,t.published_id,time FROM ( ".
    "SELECT DISTINCT FROM_UNIXTIME(add_time, '%Y%m%d') AS time, 
    published_id from qz_circle_detail".
    " where DATE_FORMAT(FROM_UNIXTIME(add_time),'%Y%m%d') = DATE_FORMAT(now(),'%Y%m%d') ".
    " and circle_id = ".$circle_id .
    " and published_id = " .$uid.
    ") t ";
  error_log('judge_if_today_punched sql is =================>'.$sql);
  $result = $this->query_row($sql);
  $count = $result['count'];
  if(!$count){
    $count =0;
  }
  return $count;
}

/**
 * 獲取用戶在某個圈子的打卡基礎數據
 * @param $uid 用戶編號
 * @param $circle_id 圈文編號
 */
public function get_user_circle_continuous_data($uid,$circle_id){
  //當月打卡次數,不傳時間則默認爲當前時間
  $current_month_punch_time = $this->model('account')->count_current_month_punch($uid,$circle_id);
  //添加連續打卡次數continuous_puch,不傳時間則默認爲當前時間
  $total_contious_punch_times = $this->model('account')->count_continueous_punch($uid,$circle_id);
  $user_info = $this->model('account')->get_user_info_by_uid($uid);
  $user_data = array();
  $user_data['uid'] = $uid;
  $user_data['user_name'] = $user_info['user_name'];
  $user_data['avatar'] = get_avatar_url($uid, 'max');
  $user_data['current_month_punch_time'] = $current_month_punch_time;
  $user_data['total_contious_punch_times'] = $total_contious_punch_times;
  return $user_data;
}


/**更新數據*/
public function update_circle_detail_by_id($update_data,$detail_id){
  $where = 'detail_id = ' . $detail_id;
  return $this->update('circle_detail',$update_data,$where);
}


/**
 * @param $uid 用戶id
 * @param $circle_id 圈子編號
 * @param $rule_key 對應茄子幣配置規則的key
 * @param $account_center_user_info 用戶授權相關的信息
 *        account_url 賬號中心的地址,在aws_controller_inc.php中配置
 *        password 密碼
 *        secret  密鑰,在aws_controller_inc.php中配置
 * @param $integral_log_data
 *        action  動作
 *        notes   註釋
 *        item_id 對應的id
 * 增加用戶的茄子幣,所有的用戶增加茄子幣的流程都走這個方法
 */
public function add_user_gold($uid, $circle_id, $rule_key, $integral_log_data = array(),
                                $account_center_user_info = null,$is_sign_in = false){
  //1、查詢配置規則中對應的茄子幣
  error_log('current_rule_key=====================================>'.$rule_key);
  $rule_data = $this->get_circle_settings_by_key($circle_id,$rule_key);
  $complex_keys = $this->get_complex_circle_gold_keys();
  if(in_array($rule_key,$complex_keys)){
    $gold = $rule_data[$rule_key.'_golds'];
  }else{
    $gold = $rule_data;
  }

  $target_gold = empty($gold) ? 0 : intval($gold);
  $rule_gold = $target_gold;
  if($target_gold > 0){ //只有設置的茄子幣大於0時候纔會去執行更新的操作
    $this->invoke_account_center_update_integral(
                    $uid, $account_center_user_info,
                    $target_gold,$integral_log_data
    );

  }else{
    if($is_sign_in){
      //3、增加用戶積分記錄
      $this->model('integral')->log(
          $uid, $integral_log_data['action'], 
          $target_gold, $integral_log_data['notes'], 
          $integral_log_data['item_id']
      );
    }
  }

  return $rule_gold;
}

/**
 * @param $uid 用戶id
 * @param $target_gold 目標茄子幣
 * @param $account_center_user_info 用戶授權相關的信息
 *        account_url 賬號中心的地址,在aws_controller_inc.php中配置
 *        password 密碼
 *        secret  密鑰,在aws_controller_inc.php中配置
 * @param $integral_log_data
 *        action  動作
 *        notes   註釋
 *        item_id 對應的id
 * 增加用戶的茄子幣,所有的用戶增加茄子幣的流程都走這個方法
 */
public function invoke_account_center_update_integral($uid, $account_center_user_info, 
                                            $target_gold, $integral_log_data = array()){
	error_log('============invoke_account_center_update_integral============');
	$data = array();
	$data['api_key'] = md5($uid.$account_center_user_info['password'].$account_center_user_info['secret']);
	$data['opt'] = '1';
	$data['uid'] = $uid;
	$data['integral'] = $target_gold;
	$data['action'] = 'circle';
	$data['platform'] = '0';
	$apiUrl = $account_center_user_info['account_url']."Api/ApiUser/updateUserIntegral";
	error_log('============apiUrl============'.$apiUrl);
	error_log('============data============'.json_encode($data));
	$ch = curl_init ();
	curl_setopt ( $ch, CURLOPT_URL, $apiUrl);
	curl_setopt ( $ch, CURLOPT_POST, 1 );
	curl_setopt ( $ch, CURLOPT_HEADER, 0 );
	curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
	curl_setopt ( $ch, CURLOPT_POSTFIELDS, $data );
	$return = curl_exec ( $ch );
	error_log('============return============'.$return);

	curl_close ($ch);
	$return = json_decode($return);

	error_log('============invoke_account_center_update_integral============');
	error_log('account_center_user_info=============>'.json_encode($account_center_user_info));
	error_log('integral_log_data=============>'.json_encode($integral_log_data));
	if($return->state == '1') {

		error_log('============invoke_account_center_update_integral SUCCESS============');
		//更新用戶的積分信息
		$update_data = array(
			'integral' => $return->msg
		);
		$rst = $this->model('account')->update_users_fields($update_data, $uid);
		error_log('============update_user_integral state============'.$rst);
		//3、增加用戶積分記錄
		$integral_log_id = $this->model('integral')->log(
		    $uid, $integral_log_data['action'], $target_gold, 
		    $integral_log_data['notes'], $integral_log_data['item_id']
		);
		
	}

}

/**
 * 處理用戶連續圖文打卡或者簽到的邏輯
 * @param $uid 用戶編號
 * @param $circle_id 圈文編號
 * @param $action 圖文打卡或者簽到的action,CIRCLE_CONTINUOUS_PIC_PUNCH表示圖文打卡,
 *  CIRCLE_CONTINUOUS_SIGN_IN表示簽到
 * @param $account_center_user_info 用戶授權相關的信息
 *        account_url 賬號中心的地址,在aws_controller_inc.php中配置
 *        password 密碼
 *        secret  密鑰,在aws_controller_inc.php中配置
 */
public function process_circle_continuous_punch($uid,$circle_id,$action,$account_user_info){

  $action_arr = array('CIRCLE_CONTINUOUS_PIC_PUNCH','CIRCLE_CONTINUOUS_SIGN_IN','CIRCLE_CONTINUOUS_PUNCH');
  if(!in_array($action,$action_arr)){
    error_log('===============action is error===================');
    return;
  }
  error_log('===============begin to process_circle_continuous_punch_or_sign_in action:');
  error_log('action_name is===>'.$action . ', circle_id====>'.$circle_id.',uid====>'.$uid);
  //action有CIRCLE_CONTINUOUS_PUNCH和CIRCLE_CONTINOUS_SIGN_IN
  if($action == 'CIRCLE_CONTINUOUS_PIC_PUNCH'){
    //針對的是圖文打卡
    $action_type = 'punch';
    $action_name = '連續圖片打卡';
    $circle_rule_key = 'continuous_pic_punch';
    $integral_log_action = 'CIRCLE_CONTINUOUS_PIC_PUNCH';
  }else if($action == 'CIRCLE_CONTINUOUS_SIGN_IN'){
    //針對的是簽到
    $action_type = 'sign_in';
    $action_name = '連續簽到';
    $circle_rule_key = 'continuous_sign_in';
    $integral_log_action = 'CIRCLE_CONTINUOUS_SIGN_IN';
  }else{
    //針對的是打卡和簽到
    $action_type = null;
    $action_name = '連續打卡';
    $circle_rule_key = 'continuous_punch';
    $integral_log_action = 'CIRCLE_CONTINUOUS_PUNCH';
  }
  //continuous_action
  $continuous_action = 'CIRCLE_CONTINUOUS';
  $account_model = $this->model('account');
  $behavior_model = $this->model('circleBehavior');
  //打卡或者簽到的的連續行爲數據
  $single_behavior = $behavior_model->get_one_by_condition($uid,$circle_id,$action);
  $time = time();
  error_log('<==========single_behavior data ==========>'.json_encode($single_behavior));

  $single_behavior_continuous_punch_day  = $this->model('account')->count_continueous_punch(
                                                              $uid,$circle_id,$time,$action_type
                                              );
  if(!$single_behavior){  //打卡或者簽到連續數據不存在
    error_log('behavior data not exist , new one and exit===========');
    //連續打卡次數continuous_puch
    $notes = 'id爲'.$uid.'的用戶在id爲'.$circle_id.'的圈子的'.$action_name.'記錄';
    $behavior_id = $behavior_model->add_behavior(
        $action,$circle_id,$uid,$single_behavior_continuous_punch_day,$notes
    );
    //計算連續行爲的值,返回是否已經發放獎勵的狀態
    $action_flag = $this->calc_user_continuous_behavior_award(
        $uid,$circle_id,$circle_rule_key,$single_behavior_continuous_punch_day,
        0,$action_name,$integral_log_action,$account_user_info
    );
    //如果當前連續值 > 大於設置的連續值,直接更新最後時間和持續的天數
    $this->update_circle_behavior(
        $time,$single_behavior_continuous_punch_day,
        $behavior_id,$action_flag
    );
  }else{
    //行爲數據存在
    $last_action_day = date('Y-m-d',$single_behavior['update_time']);
    $today = date('Y-m-d');
    $yesterday = date("Y-m-d",strtotime("-1 day"));
    //當上次的更新日期和今天相等表示今天已經簽到或者打卡
    if($last_action_day != $today){
      error_log('last_action_day is not today ===========');
      if($last_action_day == $yesterday){
        error_log('last_action_day is yestoday ,begin to compute===========');
        //此時表示是連續的
        $id = $single_behavior['id'];
        $action_flag = $this->calc_user_continuous_behavior_award(
                            $uid,$circle_id,$circle_rule_key,
                            $single_behavior_continuous_punch_day,
                            $single_behavior['action_flag'],$action_name,
                            $integral_log_action,$account_user_info
                        );
//       如果當前連續值 > 大於設置的連續值,直接更新最後時間和持續的天數
        $this->update_circle_behavior(
            $time,$single_behavior_continuous_punch_day,
            $single_behavior['id'],$action_flag
        );

      }else{
        error_log('conutious punch was shutdown ===========');
        //此時表示連續已經中斷,直接更新時間和連續天數,對於打卡和簽到來說data的值就是連續天數
        $this->update_circle_behavior($time,0,$single_behavior['id']);
      }
    }

  }
}

 /**
 * 更新圈子用戶行爲的時間和連續天數
 * @param $update_time 更新時間
 * @param $continuous_day 未打卡之前的連續天數
 * @param $behaviour_id 行爲id
 * @param $action_flag 行爲標誌,對於打卡和簽到來說,這個就是是否領取了獎勵
 */
public function update_circle_behavior($update_time,$continuous_day,
        $behaviour_id,$action_flag = null){
  $update_data = array(
    'update_time' => $update_time,
    'data' => $continuous_day + 1,
  );
  if($action_flag){
    $update_data['action_flag'] = $action_flag;
  }
  $this->model('circleBehavior')->update_behavior_by_id($update_data,$behaviour_id);
}


四、效果圖


       簽到頁面                     簽到成功頁面

blob.png     blob.png

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章