一、功能背景
繼續上一篇文章《項目功能迭代之排行榜查詢功能的實現》之後,考慮到圈子用戶曬精美的早餐圖的資源比較少,但是又想參加公司組織的圈子打卡活動,所以產品提出需要增加圈子簽到的功能。
規則:用戶簽到以圈子爲單位,每個用戶在單個圈子每天只能簽到一次,簽到之後會獲得相應的虛擬茄子幣獎勵,簽到成功之後會彈出相應的簽到信息以及虛擬茄子幣獎勵信息。
說明:打卡操作包括圖文打卡和簽到,在數據中的表現形式用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);
}
四、效果圖
簽到頁面 簽到成功頁面