Behavior.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. <?php
  2. declare (strict_types=1);
  3. namespace app\store\controller\analysis;
  4. use app\store\controller\Controller;
  5. use app\store\model\analysis\AnalysisDailyVisit;
  6. use app\store\model\analysis\AnalysisMonthlyVisit;
  7. use app\store\model\analysis\AnalysisWeeklyVisit;
  8. use app\common\service\Export as ExportService;
  9. /**
  10. * 行为分析
  11. *
  12. * Class Behavior
  13. * @package app\store\controller\analysis
  14. */
  15. class Behavior extends Controller
  16. {
  17. //行为数据导出
  18. public function exportBehaviorTrend(){
  19. $params = $this->request->param();
  20. $type = $params['type'] ?? 2; // 时间筛选类型 1-最近7天 2-最近30天 3-自定义
  21. $comp_type = $params['comp_type'] ?? 0; // 时间对比-时间筛选类型 1-该时段前7日 2-该时段前14日 3-该时段前30日 4-自定义
  22. $start = (int)($params['start'] ?? '');
  23. $end = (int)($params['end'] ?? '');
  24. $comp_start = (int)($params['comp_start'] ?? ''); // 时间对比-开始时间
  25. $comp_end = (int)($params['comp_end'] ?? ''); // 时间对比-结束时间
  26. $grain_size = $params['grain_size'] ?? 1; // 粒度 1-日粒度 2-周粒度 3-月粒度
  27. if ($type == 3 && (!$start || !$end)) {
  28. return $this->renderError('自定义区间时间不能为空');
  29. }
  30. // 根据时间筛选类型计算筛选开始结束时间
  31. if ($type == 1) { //最近7天
  32. $start = strtotime('-7 days');
  33. $end = strtotime('-1 days');
  34. } elseif ($type == 2) {//最近30天
  35. $start = strtotime('-30 days');
  36. $end = strtotime('-1 days');
  37. }
  38. if ($comp_type == 1) {//该时段前7日
  39. $comp_start = strtotime('-7 days', $start);
  40. $comp_end = strtotime('-7 days', $end);
  41. } elseif ($comp_type == 2) {//该时段前14日
  42. $comp_start = strtotime('-14 days', $start);
  43. $comp_end = strtotime('-14 days', $end);
  44. } elseif ($comp_type == 3) {//该时段前30日
  45. $comp_start = strtotime('-30 days', $start);
  46. $comp_end = strtotime('-30 days', $end);
  47. }
  48. $start = strtotime(date('Y-m-d', $start));
  49. $end = strtotime(date('Y-m-d', $end));
  50. $comp_start = $comp_start ? strtotime(date('Y-m-d', $comp_start)) : 0;
  51. $comp_end = $comp_end ? strtotime(date('Y-m-d', $comp_end)) : 0;
  52. $dimensions = self::getDimensions();
  53. $tables = [];
  54. $fields = [];
  55. $comp_fields = [];
  56. if ($grain_size == 1) {
  57. $visit_model = new AnalysisDailyVisit();
  58. } elseif ($grain_size == 2) { // 周粒度
  59. // 判断开始时间是否不满一周
  60. if (date("w",$start) != 1) {
  61. $start = strtotime('-1 monday', $start);
  62. }
  63. if ($comp_start && date("w",$comp_start) != 1) {
  64. $comp_start = strtotime('-1 monday', $comp_start);
  65. }
  66. $visit_model = new AnalysisWeeklyVisit();
  67. } elseif ($grain_size == 3) { // 月粒度
  68. // 判断开始时间是否不满一月
  69. if (date("Y-m",$start) == date("Y-m")) {
  70. $start = strtotime(last_month('Y-m', 2, $start));
  71. } else {
  72. $start = strtotime(last_month('Y-m', 1, $start));
  73. }
  74. if ($comp_start && $comp_end){
  75. if (date("Y-m",$comp_start) == date("Y-m")) {
  76. $comp_start = strtotime(last_month('Y-m', 2, $comp_start));
  77. } else {
  78. $comp_start = strtotime(last_month('Y-m', 1, $comp_start));
  79. }
  80. }
  81. $visit_model = new AnalysisMonthlyVisit();
  82. }
  83. $lists = $visit_model::where('start_time', '>=', $start)
  84. ->where('end_time', '<', $end+ 86400)
  85. ->order('ref_date', 'asc')
  86. ->select()->toArray();
  87. $data['header'] = ['序号', '时间', '打开次数','访问次数','访问人数','新访问人数','人均停留时长','次均停留时长','平均访问深度','累计访问人数','分享人数','分享次数'];
  88. $data['filename'] = '用户使用分析';
  89. $data['data'] = [];
  90. foreach ($lists as $k=>$arr){
  91. $new_list['key'] = $k+1;
  92. $new_list['ref_date'] = $arr['ref_date'];
  93. $new_list['session_cnt'] = $arr['session_cnt'];
  94. $new_list['visit_pv'] = $arr['visit_pv'];
  95. $new_list['visit_uv'] = $arr['visit_uv'];
  96. $new_list['visit_uv_new'] = $arr['visit_uv_new'];
  97. $new_list['stay_time_uv'] = $arr['stay_time_uv'];
  98. $new_list['stay_time_session'] = $arr['stay_time_session'];
  99. $new_list['visit_depth'] = $arr['visit_depth'];
  100. $new_list['visit_total'] = $arr['visit_total'];
  101. $new_list['share_uv'] = $arr['share_uv'];
  102. $new_list['share_pv'] = $arr['share_pv'];
  103. $data['data'][] = $new_list;
  104. }
  105. $res = ExportService::export($data['data'],$data['header'],$data['filename'],'列表','Xls');
  106. return $this->renderSuccess($res,'导出成功');
  107. }
  108. /*
  109. $data = [
  110. [
  111. 'id' => 'session',
  112. 'zh' => '打开次数',
  113. 'field' => 'session_cnt'
  114. ],
  115. [
  116. 'id' => 'pv',
  117. 'zh' => '访问次数',
  118. 'field' => 'visit_pv'
  119. ],
  120. [
  121. 'id' => 'uv',
  122. 'zh' => '访问人数',
  123. 'field' => 'visit_uv'
  124. ],
  125. [
  126. 'id' => 'user_new',
  127. 'zh' => '新访问人数',
  128. 'field' => 'visit_uv_new'
  129. ],
  130. [
  131. 'id' => 'staytime_uv',
  132. 'zh' => '人均停留时长',
  133. 'field' => 'stay_time_uv'
  134. ],
  135. [
  136. 'id' => 'staytime_session',
  137. 'zh' => '次均停留时长',
  138. 'field' => 'stay_time_session'
  139. ],
  140. [
  141. 'id' => 'pagecnt_session',
  142. 'zh' => '平均访问深度',
  143. 'field' => 'visit_depth'
  144. ],
  145. [
  146. 'id' => 'total_uv',
  147. 'zh' => '累计访问人数',
  148. 'field' => 'visit_total'
  149. ],
  150. [
  151. 'id' => 'share_uv',
  152. 'zh' => '分享人数',
  153. 'field' => 'share_uv'
  154. ],
  155. [
  156. 'id' => 'share_pv',
  157. 'zh' => '分享次数',
  158. 'field' => 'share_pv'
  159. ],
  160. ];
  161. */
  162. /**
  163. * 行为数据
  164. *
  165. * @return array
  166. */
  167. public function behaviorTrend()
  168. {
  169. $params = $this->request->param();
  170. $type = $params['type'] ?? 2; // 时间筛选类型 1-最近7天 2-最近30天 3-自定义
  171. $comp_type = $params['comp_type'] ?? 0; // 时间对比-时间筛选类型 1-该时段前7日 2-该时段前14日 3-该时段前30日 4-自定义
  172. $start = (int)($params['start'] ?? '');
  173. $end = (int)($params['end'] ?? '');
  174. $comp_start = (int)($params['comp_start'] ?? ''); // 时间对比-开始时间
  175. $comp_end = (int)($params['comp_end'] ?? ''); // 时间对比-结束时间
  176. $grain_size = $params['grain_size'] ?? 1; // 粒度 1-日粒度 2-周粒度 3-月粒度
  177. if ($type == 3 && (!$start || !$end)) {
  178. return $this->renderError('自定义区间时间不能为空');
  179. }
  180. // 根据时间筛选类型计算筛选开始结束时间
  181. if ($type == 1) { //最近7天
  182. $start = strtotime('-7 days');
  183. $end = strtotime('-1 days');
  184. } elseif ($type == 2) {//最近30天
  185. $start = strtotime('-30 days');
  186. $end = strtotime('-1 days');
  187. }
  188. if ($comp_type == 1) {//该时段前7日
  189. $comp_start = strtotime('-7 days', $start);
  190. $comp_end = strtotime('-7 days', $end);
  191. } elseif ($comp_type == 2) {//该时段前14日
  192. $comp_start = strtotime('-14 days', $start);
  193. $comp_end = strtotime('-14 days', $end);
  194. } elseif ($comp_type == 3) {//该时段前30日
  195. $comp_start = strtotime('-30 days', $start);
  196. $comp_end = strtotime('-30 days', $end);
  197. }
  198. $table = $this->getChartTables($start, $end, $grain_size, $comp_start, $comp_end);
  199. $data = [
  200. 'start' => date('Y-m-d', $start),
  201. 'end' => date('Y-m-d', $end),
  202. 'table' => $table
  203. ];
  204. if ($comp_start && $comp_end) {
  205. $data['comp_start'] = date('Y-m-d', $comp_start);
  206. $data['comp_end'] = date('Y-m-d', $comp_end);
  207. }
  208. return $this->renderSuccess($data);
  209. }
  210. private function getChartTables($start, $end, $grain_size, $comp_start, $comp_end)
  211. {
  212. $start = strtotime(date('Y-m-d', $start));
  213. $end = strtotime(date('Y-m-d', $end));
  214. $comp_start = $comp_start ? strtotime(date('Y-m-d', $comp_start)) : 0;
  215. $comp_end = $comp_end ? strtotime(date('Y-m-d', $comp_end)) : 0;
  216. $dimensions = self::getDimensions();
  217. $tables = [];
  218. $fields = [];
  219. $comp_fields = [];
  220. if ($grain_size == 1) {
  221. $visit_model = new AnalysisDailyVisit();
  222. } elseif ($grain_size == 2) { // 周粒度
  223. // 判断开始时间是否不满一周
  224. if (date("w",$start) != 1) {
  225. $start = strtotime('-1 monday', $start);
  226. }
  227. if ($comp_start && date("w",$comp_start) != 1) {
  228. $comp_start = strtotime('-1 monday', $comp_start);
  229. }
  230. $visit_model = new AnalysisWeeklyVisit();
  231. } elseif ($grain_size == 3) { // 月粒度
  232. // 判断开始时间是否不满一月
  233. if (date("Y-m",$start) == date("Y-m")) {
  234. $start = strtotime(last_month('Y-m', 2, $start));
  235. } else {
  236. $start = strtotime(last_month('Y-m', 1, $start));
  237. }
  238. if ($comp_start && $comp_end){
  239. if (date("Y-m",$comp_start) == date("Y-m")) {
  240. $comp_start = strtotime(last_month('Y-m', 2, $comp_start));
  241. } else {
  242. $comp_start = strtotime(last_month('Y-m', 1, $comp_start));
  243. }
  244. }
  245. $visit_model = new AnalysisMonthlyVisit();
  246. }
  247. $visit = $visit_model::where('start_time', '>=', $start)
  248. ->where('end_time', '<', $end+ 86400)
  249. ->order('ref_date', 'asc')
  250. ->select();
  251. if (!$visit->isEmpty()) {
  252. foreach ($visit as $k => $item) {
  253. foreach ($dimensions as $kk => $d) {
  254. $fields[$kk][] = [
  255. 'ratio' => '',
  256. 'refdate' => $item['ref_date'],
  257. 'value' => $visit[$k][$d['field']],
  258. ];
  259. }
  260. }
  261. }
  262. if ($comp_start && $comp_end) {
  263. $comp_visit = $visit_model::where('start_time', '>=', $comp_start)
  264. ->where('end_time', '<', $comp_end+ 86400)
  265. ->order('ref_date', 'asc')
  266. ->select();
  267. if (!$comp_visit->isEmpty()) {
  268. foreach ($comp_visit as $k => $item) {
  269. foreach ($dimensions as $kk => $d) {
  270. $comp_fields[$kk][] = [
  271. 'ratio' => '',
  272. 'refdate' => $item['ref_date'],
  273. 'value' => $comp_visit[$k][$d['field']],
  274. ];
  275. }
  276. }
  277. }
  278. }
  279. foreach ($dimensions as $kk => $d) {
  280. if ($fields) {
  281. $tables[$kk] = [
  282. 'count' => 0,
  283. 'id' => $d['id'],
  284. 'lines' => [
  285. [
  286. 'dim' => '',
  287. 'dimZh' => '',
  288. 'fields' => $fields[$kk],
  289. ]
  290. ],
  291. 'zh' => $d['zh'],
  292. ];
  293. }
  294. if ($comp_fields) {
  295. $tables[$kk]['lines'][1] = [
  296. 'dim' => 'compare',
  297. 'dimZh' => '时间对比',
  298. 'fields' => $comp_fields[$kk],
  299. ];
  300. }
  301. }
  302. return $tables;
  303. }
  304. /**
  305. * 获取统计维度
  306. *
  307. * @return array
  308. */
  309. private static function getDimensions()
  310. {
  311. $data = [
  312. [
  313. 'id' => 'session',
  314. 'zh' => '打开次数',
  315. 'field' => 'session_cnt'
  316. ],
  317. [
  318. 'id' => 'pv',
  319. 'zh' => '访问次数',
  320. 'field' => 'visit_pv'
  321. ],
  322. [
  323. 'id' => 'uv',
  324. 'zh' => '访问人数',
  325. 'field' => 'visit_uv'
  326. ],
  327. [
  328. 'id' => 'user_new',
  329. 'zh' => '新访问人数',
  330. 'field' => 'visit_uv_new'
  331. ],
  332. [
  333. 'id' => 'staytime_uv',
  334. 'zh' => '人均停留时长',
  335. 'field' => 'stay_time_uv'
  336. ],
  337. [
  338. 'id' => 'staytime_session',
  339. 'zh' => '次均停留时长',
  340. 'field' => 'stay_time_session'
  341. ],
  342. [
  343. 'id' => 'pagecnt_session',
  344. 'zh' => '平均访问深度',
  345. 'field' => 'visit_depth'
  346. ],
  347. [
  348. 'id' => 'total_uv',
  349. 'zh' => '累计访问人数',
  350. 'field' => 'visit_total'
  351. ],
  352. [
  353. 'id' => 'share_uv',
  354. 'zh' => '分享人数',
  355. 'field' => 'share_uv'
  356. ],
  357. [
  358. 'id' => 'share_pv',
  359. 'zh' => '分享次数',
  360. 'field' => 'share_pv'
  361. ],
  362. ];
  363. return $data;
  364. }
  365. }