redis = \Yii::$app->redis; } /** * @name: * @msg: 组装 redis key * @param {string} $key * @return {*} */ private function getKey(string $key): string { $redis_key = RedisKeyEnum::suffix($key, '', true) . ':' . $this->mall_id; // $redis_key = RedisKeyEnum::suffix($key, '', true) . ':' . 58; return $redis_key; } /** * @name: * @msg: 清洗 && 处理 yii2 redis 客户端拿出来的数据,处理成正常数组 * @param {array} $data * @param {string} $type * @return {*} */ private function purgeRedisRst(array $data, string $type = 'hash', string $field_name = ''): array { if (empty($data)) { return []; } $result = []; if ('hash' == $type) { foreach ($data as $key => $val) { if ($key % 2 == 0) { $keys[] = $val; } else { $values[] = $val; } } $result = array_combine($keys, $values); } elseif ('zset-good' == $type) { $result = []; foreach ($data as $dk => $dv) { if ($dk % 2 == 0) { $keys[] = $dv; } else { $values[] = $dv; } } $arr = array_combine($keys, $values); foreach ($arr as $ak => $av) { $a_keys = explode(':', $ak); $result[] = [ 'goods_id' => $a_keys[1], $field_name => $av, ]; } } return $result; } /** * @name: * @msg: 总裁驾驶窗 * @param {*} * @return {*} */ public function actionDrivingWindow() { if (!\Yii::$app->request->isAjax) { $is_display = \Yii::$app->request->get('is_display', 1);// 判断跳转是否传参 return $this->render('/census/driving-window', ['is_display' => $is_display]); } if (\Yii::$app->request->isGet) { // 汇总的数据 $window_data_default = [ 'id' => 0, 'total_users' => 0, 'total_orders' => 0, 'total_pay_money' => 0, 'total_visitors' => 0, ]; $cache_key_mall = $this->getKey(RedisKeyEnum::CENSUS_MALL); $window_data = $this->purgeRedisRst($this->redis->hgetall($cache_key_mall), 'hash'); if (empty($window_data)) { $window_data = CensusMall::find() ->select(['id', 'total_users', 'total_orders', 'total_pay_money', 'total_visitors']) ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED]) ->limit(1) ->asArray() ->one(); if (empty($window_data)) { $window_data = $window_data_default; } } $arr = []; foreach ($window_data_default as $key => $val) { $arr[$key] = $window_data[$key] ?? 0; } $window_data = $arr; // 今日的数据 $today_data_default = [ 'total_views' => 0, 'total_users' => 0, 'add_users' => 0, 'total_pay_money' => 0, 'total_visitors' => 0, ]; $date = date('Y-m-d'); $cache_key_single_day = $this->getKey(RedisKeyEnum::CENSUS_MALL_SINGLE_DATE) . ':' . $date; $today_data = $this->purgeRedisRst($this->redis->hgetall($cache_key_single_day), 'hash'); if (!empty($today_data)) { $today_data = array_merge($today_data_default, $today_data); $today_data['today_new_users'] = $today_data['add_users']; $today_data['today_total_pay_money'] = $today_data['total_pay_money']; $today_data['today_total_visitors'] = $today_data['total_visitors']; } else { $today_data = CensusMallSingleDay::find() ->select('total_views,add_users as today_new_users,total_pay_money as today_total_pay_money,total_visitors as today_total_visitors') ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'date' => $date]) ->limit(1) ->asArray() ->one(); if (empty($today_data)) { $today_data = [ 'total_views' => 0, 'today_new_users' => 0, 'today_total_pay_money' => 0, 'today_total_visitors' => 0, ]; } } // dd($window_data); $drive_window_datas = array_merge($today_data, $window_data); return $this->success('success', $drive_window_datas); } else { return $this->error('请求方式错误'); } } /** * @name: * @msg: 流量分析页面 * @param {*} * @return {*} */ public function actionFlowanAlyse() { if (!\Yii::$app->request->isAjax) { return $this->render('/census/flow-analyse'); } if (\Yii::$app->request->isGet) { /* 流量数据 + 新老客户占比数据 ------ start ---- */ $flow_datas_default = [ 'new_customers' => 0, 'total_users' => 0, 'total_visitors' => 0, 'number_of_orders' => 0, 'total_pay_people' => 0, 'total_pay_orders' => 0, 'total_pay_money' => 0, 'repurchase_people' => 0, 'repurchase_money' => 0, 'share_people' => 0, 'total_views' => 0, ]; $cache_key_flow = $this->getKey(RedisKeyEnum::CENSUS_MALL); $flow_datas = $this->purgeRedisRst($this->redis->hgetall($cache_key_flow), 'hash'); if (empty($flow_datas)) { $flow_datas = CensusMall::find() ->select('new_customers,total_users,total_visitors,number_of_orders,total_pay_people,total_pay_orders,total_pay_money,repurchase_people,repurchase_money,share_people,total_views') ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED]) ->asArray() ->one(); if (empty($flow_datas)) { $flow_datas = $flow_datas_default; } } $flow_datas = array_merge($flow_datas_default, $flow_datas); // dd($flow_datas); // 访问-支付转化率 if ($flow_datas['total_visitors'] > 0) { $flow_datas['access_pay_rate'] = bcdiv($flow_datas['total_pay_people'], $flow_datas['total_visitors'], 2); } else { $flow_datas['access_pay_rate'] = 0; } // 访问-下单转化率 if ($flow_datas['total_visitors'] > 0) { $flow_datas['access_place_order_rate'] = bcdiv($flow_datas['number_of_orders'], $flow_datas['total_visitors'], 2); } else { $flow_datas['access_place_order_rate'] = 0; } // 访客占比 if ($flow_datas['total_users'] > 0) { $flow_datas['visitors_rate'] = bcdiv($flow_datas['total_visitors'], $flow_datas['total_users'], 2); } else { $flow_datas['visitors_rate'] = 0; } // 新客户占比 if ($flow_datas['total_users'] > 0) { $flow_datas['new_user_rate'] = bcdiv($flow_datas['new_customers'], $flow_datas['total_users'], 2); } else { $flow_datas['new_user_rate'] = 0; } // 老客户占比 // if ($flow_datas['total_users'] > 0) { // $flow_datas['old_user_rate'] = bcdiv($flow_datas['regular_customers'], $flow_datas['total_users'], 2); // } else { // $flow_datas['old_user_rate'] = 0; // } $flow_datas['old_user_rate'] = bcsub(1, $flow_datas['new_user_rate'], 2); // dd($flow_datas); // 客单价 if ($flow_datas['total_pay_money'] == 0 || $flow_datas['total_pay_people'] == 0) { $flow_datas['customer_unit_price'] = 0; } else { $flow_datas['customer_unit_price'] = bcdiv($flow_datas['total_pay_money'], $flow_datas['total_pay_people'], 2); } /* 流量数据 + 新老客户占比数据 ------ end ---- */ /* 地区订单数据 ------ start ---- */ $cahce_key_region = $this->getKey(RedisKeyEnum::CENSUS_MALL_REGION); $region_datas = $this->purgeRedisRst($this->redis->hgetall($cahce_key_region), 'hash'); // dd($region_datas); if (!empty($region_datas)) { $arr = []; $time = time(); foreach ($region_datas as $rk => $rv) { $total_pay_money = $total_orders = 0; $strs = explode('_', $rk); $province_id = array_pop($strs); if (false !== strpos($rk, 'total_pay_money')) { $total_pay_money = $rv; } if (false !== strpos($rk, 'total_orders')) { $total_orders = $rv; } $arr[$province_id]['id'] = 0; $arr[$province_id]['province_id'] = $province_id; if (empty($arr[$province_id]['total_orders'])) { $arr[$province_id]['total_orders'] = $total_orders; } if (empty($arr[$province_id]['total_pay_money'])) { $arr[$province_id]['total_pay_money'] = $total_pay_money; } $arr[$province_id]['updated_at'] = $time; } // dd($region_datas, $arr); $region_datas = array_values($arr); } else { $region_datas = CensusMallRegion::find() ->select('id,province_id,total_orders,total_pay_money,updated_at') ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED]) ->asArray() ->all(); } // dd($region_datas); $province_ids = array_column($region_datas, 'province_id'); $provinces = Region::find() ->select('id,name,short_title,areacode,initial') ->where(['id' => $province_ids, 'level' => 1]) ->asArray() ->indexBy('id') ->all(); // 地图数据 $map_order_datas = []; foreach ($region_datas as &$rval) { $province = $provinces[$rval['province_id']] ?? []; $rval['province_name'] = $province['name'] ?? '未知'; $rval['province_short_title'] = $province['short_title'] ?? ''; $rval['areacode'] = $province['areacode'] ?? ''; $rval['initial'] = $province['initial'] ?? ''; $map_order_datas[] = [ 'name' => $province['name'] ?? '', 'value' => $rval['total_orders'] ?? 0, ]; } /* 地区订单数据 ------ end ---- */ /* 商品流量排行榜 ------ start ---- */ $cache_key_good_views_ranking = $this->getKey(RedisKeyEnum::CENSUS_MALL_GOODS_VIEWS); $good_rankings = $this->purgeRedisRst($this->redis->zrevrange($cache_key_good_views_ranking, 0, -1, 'WITHSCORES'), 'zset-good', 'total_views'); // dd($good_rankings); if (empty($good_rankings)) { $good_rankings = CensusMallGoods::find() ->select('id,goods_id,total_views') ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED]) ->orderBy('total_views desc') ->limit(6) ->asArray() ->all(); } if (!empty($good_rankings)) { $goods_ids = array_column($good_rankings, 'goods_id'); $goods = Goods::find() ->select('id,goods_name,cover_pic') ->where(['mall_id' => $this->mall_id, 'id' => $goods_ids]) ->asArray() ->indexBy('id') ->all(); foreach ($good_rankings as &$ranking) { $good = $goods[$ranking['goods_id']] ?? []; $ranking['goods_name'] = $good['goods_name'] ?? ''; $ranking['cover_pic'] = $good['cover_pic'] ?? ''; } } /* 商品流量排行榜 ------ end ---- */ /* 新老客户占比饼图 ------ start ---- */ $pie_chart_datas = [ 'total_users' => $flow_datas['total_users'] ?? 0, 'names' => ['新客户占比', '老客户占比'], 'data' => [ bcmul($flow_datas['new_user_rate'], 100, 2), bcmul($flow_datas['old_user_rate'], 100, 2), ], ]; /* 新老客户占比饼图 ------ end ---- */ // dd($flow_datas, $region_datas, $good_rankings); $data = [ 'flow_datas' => $flow_datas, 'region_datas' => $region_datas, 'good_rankings' => $good_rankings, 'map_order_datas' => $map_order_datas, 'pie_chart_datas' => $pie_chart_datas, ]; return $this->success('success', $data); } else { return $this->error('请求方式错误'); } } /** * @name: * @msg: 商品数据统计 * @param {*} * @return {*} */ public function actionGoodsStatistics() { if (!\Yii::$app->request->isAjax) { return $this->render('/census/goods-statistics'); } /* 顶部汇总数据 ---- start ------ */ $cache_key_goods_statistics = $this->getKey(RedisKeyEnum::CENSUS_MALL); $goods_statistics = $this->purgeRedisRst($this->redis->hgetall($cache_key_goods_statistics), 'hash'); $goods_statistics_default = [ 'id' => 0, 'goods_total_visitors' => 0, 'goods_total_views' => 0, 'total_views' => 0, 'total_pay_people' => 0, 'total_pay_money' => 0, 'goods_listings' => 0, 'repurchase_people' => 0, 'repurchase_money' => 0, 'updated_at' => 0, ]; if (!empty($goods_statistics)) { $goods_statistics = array_merge($goods_statistics_default, $goods_statistics); } else { $goods_statistics = CensusMall::find() ->select('id,goods_total_visitors,total_views,total_pay_people,total_pay_money,goods_listings,repurchase_people,repurchase_money,updated_at') ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED]) ->asArray() ->one(); if (empty($goods_statistics)) { $goods_statistics = [ 'id' => 0, 'goods_total_visitors' => 0, 'goods_total_views' => 0, 'total_views' => 0, 'total_pay_people' => 0, 'total_pay_money' => 0, 'goods_listings' => 0, 'repurchase_people' => 0, 'repurchase_money' => 0, 'updated_at' => 0, ]; } } // 客单价 if ($goods_statistics['total_pay_money'] == 0 || $goods_statistics['total_pay_people'] == 0) { $goods_statistics['customer_unit_price'] = 0; } else { $goods_statistics['customer_unit_price'] = bcdiv($goods_statistics['total_pay_money'], $goods_statistics['total_pay_people'], 2); } /* 顶部汇总数据 ---- end ------ */ /* 商品排行榜 --- start --- */ $goods_ids = []; $cache_key_good_views_ranking = $this->getKey(RedisKeyEnum::CENSUS_MALL_GOODS_VIEWS); $good_views_ranking = $this->purgeRedisRst($this->redis->zrevrange($cache_key_good_views_ranking, 0, 4, 'WITHSCORES'), 'zset-good', 'total_views'); if (empty($good_views_ranking)) { $good_views_ranking = CensusMallGoods::find() ->select('goods_id,total_views') ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED]) ->limit(5) ->asArray() ->all(); } $goods_ids = array_merge($goods_ids, array_column($good_views_ranking, 'goods_id')); $cahce_key_good_sales_ranking = $this->getKey(RedisKeyEnum::CENSUS_MALL_GOODS_SALES_VOLUME); $good_sales_ranking = $this->purgeRedisRst($this->redis->zrevrange($cahce_key_good_sales_ranking, 0, 4, 'WITHSCORES'), 'zset-good', 'sales_volumes'); if (empty($good_sales_ranking)) { $good_sales_ranking = CensusMallGoods::find() ->select('goods_id,total_sales_volume') ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED]) ->limit(5) ->asArray() ->all(); } $goods_ids = array_merge($goods_ids, array_column($good_sales_ranking, 'goods_id')); $cache_key_paymoney = $this->getKey(RedisKeyEnum::CENSUS_MALL_GOODS_PAY_MONEY); $good_paymoney_ranking = $this->purgeRedisRst($this->redis->zrevrange($cache_key_paymoney, 0, 4, 'WITHSCORES'), 'zset-good', 'pay_amounts'); if (empty($good_paymoney_ranking)) { $good_sales_ranking = CensusMallGoods::find() ->select('goods_id,total_pay_money') ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED]) ->limit(5) ->asArray() ->all(); } $goods_ids = array_merge($goods_ids, array_column($good_sales_ranking, 'goods_id')); $cache_key_visitors = $this->getKey(RedisKeyEnum::CENSUS_MALL_GOODS_VISITORS); $good_visitor_ranking = $this->purgeRedisRst($this->redis->zrevrange($cache_key_visitors, 0, 4, 'WITHSCORES'), 'zset-good', 'access_times'); if (empty($good_visitor_ranking)) { $good_rankings = CensusMallGoods::find() ->select('goods_id,total_visitors') ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED]) ->limit(5) ->asArray() ->all(); } $goods_ids = array_unique(array_merge($goods_ids, array_column($good_sales_ranking, 'goods_id'))); $goods = Goods::find() ->select('id,goods_name,cover_pic') ->where(['mall_id' => $this->mall_id, 'id' => $goods_ids]) ->asArray() ->indexBy('id') ->all(); if (!empty($good_sales_ranking)) { foreach ($good_sales_ranking as $sk => &$sv) { if ($sk >= 5) { break; } $good = $goods[$sv['goods_id']] ?? []; $sv['goods_name'] = $good['goods_name'] ?? ''; $sv['cover_pic'] = $good['cover_pic'] ?? ''; } } else { $good_sales_ranking = []; } if (!empty($good_views_ranking)) { foreach ($good_views_ranking as $vk => &$vv) { if ($vk >= 5) { break; } $good = $goods[$vv['goods_id']] ?? []; $vv['goods_name'] = $good['goods_name'] ?? ''; $vv['cover_pic'] = $good['cover_pic'] ?? ''; $list[] = $vv; } } else { $good_views_ranking = []; } if (!empty($good_paymoney_ranking)) { foreach ($good_paymoney_ranking as $pk => &$pv) { if ($pk >= 5) { break; } $good = $goods[$pv['goods_id']] ?? []; $pv['goods_name'] = $good['goods_name'] ?? ''; $pv['cover_pic'] = $good['cover_pic'] ?? ''; $pv['pay_amounts'] = bcadd($pv['pay_amounts'], 0, 2); } } else { $good_paymoney_ranking = []; } if (!empty($good_visitor_ranking)) { foreach ($good_visitor_ranking as $vik => &$viv) { if ($vik >= 5) { break; } $good = $goods[$viv['goods_id']] ?? []; $viv['goods_name'] = $good['goods_name'] ?? ''; $viv['cover_pic'] = $good['cover_pic'] ?? ''; } } else { $good_visitor_ranking = []; } /* 商品排行榜 --- end --- */ /* 中间部分 GMV 的数据 --- start --- */ $day_numbers = 15; $date_time = DateHelper::someDays($day_numbers, 'before'); $start_time = $date_time['start']; $endDate = new \DateTime('yesterday'); $endDate->setTime(23, 59, 59); $end_time = $endDate->getTimestamp(); $gmv_data = CensusMallSingleDay::find() ->select('id,total_order_money,date,updated_at') ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED]) ->andWhere(['and', ['>=', 'created_at', $start_time], ['<', 'created_at', $end_time]]) ->orderBy('updated_at asc') ->asArray() ->all(); $keys = []; $values = []; for ($j = 0; $j < $day_numbers; $j++) { $date_timep = DateHelper::someDays($j + 1, 'before'); $keys[] = date('m-d', $date_timep['start']); } $keys = array_reverse($keys); if (!empty($gmv_data)) { foreach ($gmv_data as $val) { $k = date('m-d', strtotime($val['date'] . ' 00:00:00')); $date_data_map[$k] = $val['total_order_money']; } foreach ($keys as $v) { $values[] = $date_data_map[$v] ?? 0; } } else { for ($i = 0; $i < $day_numbers; $i++) { $values[] = 0; } } $gmvs = [ 'keys' => $keys, 'values' => $values, ]; /* 中间部分 GMV 的数据 --- end --- */ $data = [ 'goods_data' => $goods_statistics, 'access_rankings' => $good_visitor_ranking, 'paymoney_rankings' => $good_paymoney_ranking, 'sales_rankings' => $good_sales_ranking, 'gmvs' => $gmvs, ]; return $this->success('success', $data); } }