request->param(); $type = $params['type'] ?? 2; // 时间筛选类型 1-最近7天 2-最近30天 3-自定义 $start = (int)($params['start'] ?? ''); $end = (int)($params['end'] ?? ''); $retain_type = $params['retain_type'] ?? 1; // 类型 1-新增用户留存 2-活跃用户留存 $grain_size = $params['grain_size'] ?? 1; // 粒度 1-日粒度 2-周粒度 3-月粒度 if ($type == 3 && (!$start || !$end)) { return $this->renderError('自定义区间时间不能为空'); } // 根据时间筛选类型计算筛选开始结束时间 if ($type == 1) { //最近7天 $start = strtotime('-7 days'); $end = strtotime('-1 days'); } elseif ($type == 2) {//最近30天 $start = strtotime('-30 days'); $end = strtotime('-1 days'); } $table = $this->getChartTables($start, $end, $retain_type, $grain_size); $data = []; $data['header'] = ['序号', '时间', '新增用户数','1天后','2天后','3天后','4天后','5天后','6天后','7天后','14天后','30天后']; $data['filename'] = '用户留存分析'; $data['data'] = []; foreach ($table as $k=>$arr){ $new_list['key'] = $k+1; $new_list['ref_date'] = $arr['ref_date']; $new_list['retain_0'] = $arr['retain_0']; $new_list['retain_1'] = $arr['retain_1']; $new_list['retain_2'] = $arr['retain_2']; $new_list['retain_3'] = $arr['retain_3']; $new_list['retain_4'] = $arr['retain_4']; $new_list['retain_5'] = $arr['retain_5']; $new_list['retain_6'] = $arr['retain_6']; $new_list['retain_7'] = $arr['retain_7']; $new_list['retain_14'] = $arr['retain_14']; $new_list['retain_30'] = $arr['retain_30']; $data['data'][] = $new_list; } $res = ExportService::export($data['data'],$data['header'],$data['filename'],'列表','Xls'); return $this->renderSuccess($res,'导出成功'); } /** * 留存数据 * * @return array */ public function retainData() { $params = $this->request->param(); $type = $params['type'] ?? 2; // 时间筛选类型 1-最近7天 2-最近30天 3-自定义 $start = (int)($params['start'] ?? ''); $end = (int)($params['end'] ?? ''); $retain_type = $params['retain_type'] ?? 1; // 类型 1-新增用户留存 2-活跃用户留存 $grain_size = $params['grain_size'] ?? 1; // 粒度 1-日粒度 2-周粒度 3-月粒度 if ($type == 3 && (!$start || !$end)) { return $this->renderError('自定义区间时间不能为空'); } // 根据时间筛选类型计算筛选开始结束时间 if ($type == 1) { //最近7天 $start = strtotime('-7 days'); $end = strtotime('-1 days'); } elseif ($type == 2) {//最近30天 $start = strtotime('-30 days'); $end = strtotime('-1 days'); } $table = $this->getChartTables($start, $end, $retain_type, $grain_size); $data = [ 'start' => date('Y-m-d', $start), 'end' => date('Y-m-d', $end), 'table' => $table ]; return $this->renderSuccess($data); } private function getChartTables($start, $end, $retain_type, $grain_size) { $start = strtotime(date('Y-m-d', $start)); $end = strtotime(date('Y-m-d', $end)); if ($retain_type == AnalysisDailyRetainTag::TYPE_NEW) { $with = 'retainTagNew'; } elseif($retain_type == AnalysisDailyRetainTag::TYPE_ACTIVE) { $with = 'retainTagActive'; } else { return $this->renderError('留存类型参数无效'); } $retainDays = self::getRetainDays($grain_size); if ($grain_size == 1) { // 日粒度 $retainModel = new AnalysisDailyRetainModel(); } elseif ($grain_size == 2) { // 周粒度 $retainModel = new AnalysisWeeklyRetainModel(); // 判断开始时间是否不满一周 if (date("w",$start) != 1) { $start = strtotime('-1 monday', $start); } } elseif ($grain_size == 3) { // 月粒度 $retainModel = new AnalysisMonthlyRetainModel(); // 判断开始时间是否不满一月 if (date("Y-m",$start) == date("Y-m")) { $start = strtotime(last_month('Y-m', 2, $start)); } else { $start = strtotime(last_month('Y-m', 1, $start)); } } $list = $retainModel::where('start_time', '>=', $start) ->where('end_time', '<', $end+ 86400) ->field('id,ref_date') ->with($with) ->order('ref_date', 'desc') ->paginate() ->each(function ($v) use ($with, $retainDays) { $tags = []; foreach ($v[$with] as $vv) { $tags[$vv['key']] = $vv['value']; } foreach ($retainDays as $kk=>$rd) { $retain_first = $tags[0]; // 当日 if (isset($tags[$rd])) { if ($rd > 0) { if ($tags[$rd] > 0 && $retain_first > 0) { $v["retain_{$rd}"] = round(($tags[$rd] / $retain_first)*100, 2); } else { $v["retain_{$rd}"] = 0; } } else { $v["retain_{$rd}"] = $tags[$rd]; } } else { $v["retain_{$rd}"] = ''; } } unset($v['id'],$v[$with]); }); return $list; } private static function getRetainDays($grain_size) { if ($grain_size == 1) { return [0,1,2,3,4,5,6,7,14,30]; } elseif ($grain_size == 2) { return [0,1,2,3,4]; } elseif ($grain_size == 3) { return [0,1]; } else { return []; } } }