// +---------------------------------------------------------------------- namespace App\Services\Api; use App\Models\TaskLogModel; use App\Models\TaskModel; use App\Services\BaseService; use App\Services\RedisService; use BN\Red; use Illuminate\Support\Facades\DB; /** * 任务管理-服务类 * @author laravel开发员 * @since 2020/11/11 * @package App\Services\Api */ class TaskService extends BaseService { // 静态对象 protected static $instance = null; /** * 构造函数 * @author laravel开发员 * @since 2020/11/11 * GoodsService constructor. */ public function __construct() { $this->model = new TaskModel(); } /** * 静态入口 * @return static|null */ public static function make() { if (!self::$instance) { self::$instance = (new static()); } return self::$instance; } /** * 每日任务 * @param $params * @param int $pageSize * @return array */ public function getTaskList($userId, $type=1) { $datas = $this->model->where(['type'=>$type,'status'=>1,'mark'=>1]) ->select(['id','name','type','num','power','sort','check_type','scene']) ->orderBy('sort','desc') ->orderBy('id','desc') ->get(); $datas = $datas? $datas->toArray() : []; $power = 0; $num = 0; $complete = 0; if($datas){ foreach ($datas as &$item){ $item['status'] = 1; if($power<=0){ $power = $item['power']; } $logNum = $this->getLogNum($userId, $item['id'], $item['type']); // 次数 $item['log_num'] = $logNum; if($item['check_type'] == 1 && $item['num']<=$logNum){ $item['status'] = 2; $item['log_num'] = $item['num']; $complete++; } // 时长 else if($item['check_type'] == 2 && $logNum>0){ $item['status'] = 2; $item['log_num'] = 1; $complete++; } } unset($item); } return ['power'=>$power,'complete'=>$complete,'num'=>count($datas), 'list'=> $datas]; } /** * 任务完成情况 * @param $userId * @param $taskId * @param int $type * @return array|mixed */ public function getLogNum($userId, $taskId, $type=1) { $cacheKey = "caches:task:check_{$userId}_{$taskId}_{$type}"; $data = RedisService::get($cacheKey); if($data){ return $data; } $data = TaskLogModel::where(['task_id'=> $taskId,'user_id'=> $userId,'status'=>1,'mark'=>1]) ->where(function($query) use($type){ // 每日任务 if($type == 1){ $query->where('date','=', date('Y-m-d')); } })->value('num'); if($data){ RedisService::set($cacheKey, $data, rand(3,5)); } return $data; } /** * 获取对应场景下的任务列表 * @param $scene 场景 * @return array|mixed */ public function getTaskByScene($scene) { $cacheKey = "caches:task:scene_{$scene}"; $datas = RedisService::get($cacheKey); if($datas){ return $datas; } $where = ['scene'=> $scene,'status'=>1,'mark'=>1]; $datas = $this->model->where($where) ->select(['id','name','type','num','power','sort','check_type','scene']) ->orderBy('sort','desc') ->orderBy('id','desc') ->get(); $datas = $datas? $datas->toArray() : []; if($datas) { RedisService::set($cacheKey, $datas, rand(300,600)); } return $datas; } /** * 获取对应类型的任务列表 * @param $type 类型:1-每日任务,2-新手任务 * @return array|mixed */ public function getTaskByType($type) { $cacheKey = "caches:task:type_{$type}"; $datas = RedisService::get($cacheKey); if($datas){ return $datas; } $datas = $this->model->where(['type'=> $type,'status'=>1,'mark'=>1]) ->select(['id','name','type','num','power','sort','check_type','scene']) ->orderBy('sort','desc') ->orderBy('id','desc') ->get(); $datas = $datas? $datas->toArray() : []; if($datas) { RedisService::set($cacheKey, $datas, rand(300,600)); } return $datas; } /** * 验证更新任务完成记录数据 * @param $userId 用户ID * @param $taskId 任务ID * @param int $type 任务类型:1-每日,2-新手 * @param int $checkType 任务验证类型:1-次数,2-时长 * @param int $sourceId 任务完成对象来源ID * @return false */ public function updateLogData($userId, $taskId, $type=1, $checkType=1, $sourceId=0) { $cacheKey = "caches:task:scene_update_{$userId}_{$taskId}_{$type}"; if(RedisService::get($cacheKey)){ return false; } // 是否已经完成 $checkData = TaskLogModel::where(['task_id'=> $taskId,'user_id'=> $userId,'is_complete'=>1,'status'=>1,'mark'=>1]) ->where(function($query) use($type){ // 每日任务 if($type == 1){ $query->where('date','=', date('Y-m-d')); } })->select(['id','task_id','user_id'])->orderBy('id','desc')->first(); if($checkData){ RedisService::set($cacheKey, $checkData, rand(300,600)); return false; } // 清除缓存 RedisService::clear("caches:task:check_{$userId}_{$taskId}_{$type}"); $logId = TaskLogModel::where(['task_id'=> $taskId,'user_id'=> $userId,'status'=>1,'mark'=>1]) ->where(function($query) use($type){ // 每日任务 if($type == 1){ $query->where('date','=', date('Y-m-d')); } })->value('id'); if($logId){ if($checkType == 1){ $updateData = ['num'=> DB::raw('num + 1'),'update_time'=>time()]; }else{ $updateData = ['num'=> 1,'update_time'=>time()]; } return TaskLogModel::where(['id'=> $logId])->update($updateData); }else{ return TaskLogModel::insert([ 'user_id'=> $userId, 'task_id'=> $taskId, 'source_id'=> $sourceId, 'num'=> 1, 'date'=> date('Y-m-d'), 'create_time'=> time(), 'update_time'=> time(), 'status'=>1, 'mark'=>1, ]); } } /** * 验证更新任务完成状态,并结算 * @param $userId 用户ID * @param $scene 场景 * @param int $sourceId 来源ID * @return false */ public function updateTask($userId, $scene, $sourceId=0,$time=0) { $taskList = $this->getTaskByScene($scene); RedisService::set("caches:task:temp_{$userId}_{$scene}_{$sourceId}", ['datas'=>$taskList,'date'=>date('Y-m-d H:i:s')], 600); if($taskList){ $hasDay = false; $completeIds = []; foreach ($taskList as $item){ $item['status'] = 1; $taskId = isset($item['id'])? $item['id'] : 0; $checkType = isset($item['check_type'])? $item['check_type'] : 1; $type = isset($item['type'])? $item['type'] : 1; $num = isset($item['num'])? $item['num'] : 1; $taskName = isset($item['name']) && $item['name']? $item['name'] : '任务'; $power = isset($item['power'])? floatval($item['power']) : 0; // 验证更新完成记录,若无数据更新则跳过 $errorKey = "caches:task:scene_error:{$taskId}_{$userId}"; if(!$this->updateLogData($userId, $taskId, $type, $checkType, $sourceId)){ RedisService::set("{$errorKey}_error", ['info'=> $item,'user_id'=> $userId,'source_id'=> $sourceId,'error'=>'该任务已完成'], rand(300, 600)); continue; } // 获取验证数据 $logNum = $this->getLogNum($userId, $taskId, $type); // 次数 if($item['check_type'] == 1 && $num<=$logNum){ $item['status'] = 2; $item['log_num'] = $logNum; } // 时长 else if($item['check_type'] == 2 && $logNum>0 && $num <= ($time/60)){ $item['status'] = 2; $item['log_num'] = $logNum; } // 新手任务奖励 if($type == 2 && $item['status'] == 2) { FinanceService::make()->settleTaskPower($userId, $power, $taskId, "完成{$taskName}任务奖励"); $completeIds[] = $taskId; }else if($type == 1 && $item['status'] == 2){ $hasDay = true; } } // 更新完成 if($completeIds){ TaskLogModel::whereIn('task_id',$completeIds)->update(['is_complete'=>1,'update_time'=>time()]); } // 当前有每日任务,处理 if($hasDay){ $dayTaskList = $this->getTaskByType(1); if($dayTaskList){ $power = 0; $completeCount = 0; $ids[] = []; foreach ($dayTaskList as $item){ $taskId = isset($item['id'])? $item['id'] : 0; $type = isset($item['type'])? $item['type'] : 1; $num = isset($item['num'])? $item['num'] : 1; // 获取验证数据 $logNum = $this->getLogNum($userId, $taskId, $type); // 次数 if($item['check_type'] == 1 && $num<=$logNum){ $completeCount++; } // 时长 else if($item['check_type'] == 2 && $logNum>0 && $num <= ($time/60)){ $completeCount++; } if($power<=0){ $power = isset($item['power'])? $item['power'] : 0; } $ids[] = $taskId; } // 所有任务完成 if($completeCount == count($dayTaskList)){ FinanceService::make()->settleTaskPower($userId, $power, 0, "完成每日任务奖励"); // 今日任务更新完成 if($ids){ TaskLogModel::whereIn('task_id',$ids)->where('date','>=',date('Y-m-d'))->update(['is_complete'=>1,'update_time'=>time()]); } } } } } } }