getLine() . '行,错误信息:' .$e->getMessage(); } return ['status' => $status, 'data' => $data, 'msg' => $msg]; } /** * 获取系统状态 * @Author:lun * @Date:2024-09-18 18:51 * @Copyright:copyright(c)2024 广东七件事集团 * @return array */ public static function getLinuxStatus() { $cpu = self::getCpuUsagePercent(); $memory = self::getMemoryPercent(); $disk = self::getDiskPercent(); $redis = self::getRedisPercent(); $site_num = Mall::getMallCount(); return compact('cpu', 'memory', 'disk', 'redis', 'site_num'); } /** * 获取内存使用率 * @Author:lun * @Date:2024-09-18 18:46 * @Copyright:copyright(c)2024 广东七件事集团 * @return array */ public static function getMemoryPercent() { exec('free -m', $output); $memoryInfo = explode("\n", $output[1]); $memoryParts = preg_split('/\s+/', $memoryInfo[0]); $total = $memoryParts[1];// 总内存 $use_total = $memoryParts[2];// 已使用内存 $freeMemory = $memoryParts[3];// 可用内存 $percent = round(($use_total / $total) * 100, 2); return compact('use_total','total','percent'); } /** * 获取磁盘使用率 * @Author:lun * @Date:2024-09-19 17:20 * @Copyright:copyright(c)2024 广东七件事集团 * @return array */ public static function getDiskPercent() { $use_total = $percent = 0; $total = disk_total_space("/"); // 更改为你想检测的磁盘路径 if ($total == 0) return compact('use_total','total','percent'); // 检测磁盘剩余空间 $freeDiskSpace = disk_free_space("/"); // 更改为你想检测的磁盘路径 // 计算磁盘使用率 $use_total = $total - $freeDiskSpace; $percent = round(($use_total / $total) * 100, 2); return compact('use_total','total','percent'); } /** * 获取CPU使用率 * @Author:lun * @Date:2024-09-18 18:46 * @Copyright:copyright(c)2024 广东七件事集团 * @return float */ public static function getCpuUsagePercent() { $prevStats = self::getCpuStats(); sleep(1); $currStats = self::getCpuStats(); $prevIdle = $prevStats['idle'] + $prevStats['iowait']; $prevNonIdle = $prevStats['user'] + $prevStats['nice'] + $prevStats['system'] + $prevStats['irq'] + $prevStats['softirq']; $prevTotal = $prevIdle + $prevNonIdle; $currIdle = $currStats['idle'] + $currStats['iowait']; $currNonIdle = $currStats['user'] + $currStats['nice'] + $currStats['system'] + $currStats['irq'] + $currStats['softirq']; $currTotal = $currIdle + $currNonIdle; $diffTotal = $currTotal - $prevTotal; $diffIdle = $currIdle - $prevIdle; return round((1 - $diffIdle / $diffTotal) * 100); } /** * 获取CPU使用情况 * @Author:lun * @Date:2024-09-18 18:46 * @Copyright:copyright(c)2024 广东七件事集团 * @return int[] */ public static function getCpuStats() { exec('cat /proc/stat', $output); $parts = preg_split('/\s+/', $output[0]); return [ 'user' => (int)$parts[1], 'nice' => (int)$parts[2], 'system' => (int)$parts[3], 'idle' => (int)$parts[4], 'iowait' => (int)$parts[5], 'irq' => (int)$parts[6], 'softirq' => (int)$parts[7] ]; } /** * 获取Redis使用率 * @Author:lun * @Date:2024-09-19 16:57 * @Copyright:copyright(c)2024 广东七件事集团 * @return array */ public static function getRedisPercent() { $redis = Yii::$app->redis; // 执行 INFO 命令 $info = $redis->executeCommand('INFO', ['memory']); $lines = explode("\r\n", $info); $memoryUsage = []; foreach ($lines as $line) { if (strpos($line, ':') !== false) { list($key, $value) = explode(':', $line, 2); $memoryUsage[$key] = $value; } } $percent = 0; $use_total = empty($memoryUsage['use_memory']) ? 0 : $memoryUsage['use_memory'] / (1024 * 1024);// 已使用内存 $total = empty($memoryUsage['maxmemory']) ? 0 : $memoryUsage['maxmemory'] / (1024 * 1024);// 最大内存 if ($use_total > 0 && $total > 0) {// Redis 未开启内存限制,则返回 0 $percent = round(($use_total / $total) * 100, 2); } return compact('use_total', 'total', 'percent'); } /** * 概括数据 * @return array */ public static function getWraparound() { $oneStatus = [ 'total_money' => 0, 'total_users' => 0, 'total_orders' => 0, 'total_sales' => 0, 'total_profit' => 0, ]; // 获取一级概括数据 try { $mallModel = CensusMall::find() ->distinct('mall_id') ->where(['status' => StatusEnum::ENABLED]) ->asArray() ->orderBy('id desc'); $batchSize = 1000; foreach ($mallModel->batch($batchSize) as $mallList) { foreach ($mallList as $item) { $oneStatus['total_users'] += $item['total_users']; $oneStatus['total_orders'] += $item['total_orders']; $oneStatus['total_money'] = bcadd($oneStatus['total_money'], $item['total_pay_money'], 2); } } } catch (\Exception $e) { // 处理异常 Yii::error("Error fetching mall data: " . $e->getMessage()); } // 获取一级概括数据 try { $mallGoodsModel = CensusMallGoods::find() ->distinct('mall_id') ->where(['status' => StatusEnum::ENABLED]) ->asArray() ->orderBy('id desc'); foreach ($mallGoodsModel->batch($batchSize) as $mallGoodsList) { foreach ($mallGoodsList as $item) { $oneStatus['total_sales'] += $item['total_sales_volume']; } } } catch (\Exception $e) { // 处理异常 Yii::error("Error fetching mall goods data: " . $e->getMessage()); } // 获取总利润(不计算已关闭订单) try { $orderDetailModel = OrderDetail::find() ->where(['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]) ->andWhere(['!=', 'order_status', OrderStatusEnum::REPEAL]) ->asArray() ->orderBy('id desc'); foreach ($orderDetailModel->batch($batchSize) as $orderDetailList) { foreach ($orderDetailList as $item) { $profit = bcsub($item['goods_price'], bcmul($item['cost_price'], $item['num'], 2), 2); $oneStatus['total_profit'] = bcadd($oneStatus['total_profit'], $profit, 2); } } } catch (\Exception $e) { // 处理异常 Yii::error("Error fetching order detail data: " . $e->getMessage()); } // 获取销售额排名 try { $yesterdayDate = date('Ymd', strtotime('-1 day')); $yesterdayMoneySubquery = (new \yii\db\Query()) ->select('sum(pay_money) as total_money') ->from(UserStatistics::tableName() . ' ut2') ->where(['ut.mall_id' => new \yii\db\Expression('ut2.mall_id'), 'ut2.status' => 1, 'ut2.date' => $yesterdayDate]); $threeStatus['total_achievement_ranking'] = UserStatisticsTotal::find() ->alias('ut') ->leftJoin(Mall::tableName() . ' mall', 'mall.id=ut.mall_id') ->select([ 'sum(ut.pay_money) as total_money', 'mall.name as mall_name', 'mall.id as mall_id', 'IFNULL((' . $yesterdayMoneySubquery->createCommand()->getRawSql() . '), 0) as yesterdayMoney' ]) ->where(['ut.status' => StatusEnum::ENABLED]) ->groupBy('ut.mall_id') ->orderBy('total_money desc') ->limit(10) ->asArray() ->all(); foreach ($threeStatus['total_achievement_ranking'] as &$item) { $item['logo'] = Yii::$app->services->setting->mall->get($item['mall_id'], 'basic.logo'); if (empty($item['logo'])) { $item['logo'] = Yii::$app->request->hostInfo . '/resources/img/admin/mall-logo.png'; } } unset($item); } catch (\Exception $e) { // 处理异常 Yii::error("Error fetching achievement ranking data: " . $e->getMessage()); } // 获取热销商品排名 $threeStatus['sales_volume_ranking'] = CensusMallGoods::find() ->with([ 'goods' => function ($query) { $query->select(['id', 'goods_name', 'cover_pic']); }, 'mall' => function ($query) { $query->select(['id', 'name']); } ]) ->where(['status' => StatusEnum::ENABLED]) ->orderBy('total_pay_money desc') ->select('total_pay_money, goods_id, mall_id') ->limit(10) ->asArray() ->all(); // 获取热销商品排名 $threeStatus['hot_sales_goods_ranking'] = CensusMallGoods::find() ->with([ 'goods' => function ($query) { $query->select(['id', 'goods_name', 'cover_pic']); }, 'mall' => function ($query) { $query->select(['id', 'name']); } ]) ->where(['status' => StatusEnum::ENABLED]) ->orderBy('total_sales_volume desc') ->select('total_sales_volume, goods_id, mall_id') ->limit(10) ->asArray() ->all(); $threeStatus['sales_volume_ranking'] = self::getSalesRanking('total_pay_money'); $threeStatus['hot_sales_goods_ranking'] = self::getSalesRanking('total_sales_volume'); return compact('oneStatus', 'threeStatus'); } public static function getSalesRanking($orderByField): array { try { return CensusMallGoods::find() ->with([ 'goods' => function ($query) { $query->select(['id', 'goods_name', 'cover_pic']); }, 'mall' => function ($query) { $query->select(['id', 'name']); } ]) ->where(['status' => StatusEnum::ENABLED]) ->orderBy($orderByField . ' desc') ->select([$orderByField, 'goods_id', 'mall_id']) ->limit(10) ->asArray() ->all(); } catch (\Exception $e) { // 处理异常 Yii::error("Error fetching sales ranking data: " . $e->getMessage()); return []; } } public static function getSaleTrend() { // 获取用户活跃度 $currentDate = date('Y-m-d', time()); $saleTrendList = []; // 获取用户活跃度数据 $censusMall = CensusMallSingleDay::find() ->where(['status' => StatusEnum::ENABLED]) ->select('date, sum(total_actives) as total_actives, sum(add_users) as add_users, sum(add_pay_people_nums) as add_pay_people_nums') ->groupBy('date') ->asArray() ->all(); if (!empty($censusMall)) $censusMall = array_column($censusMall, null, 'date'); for ($i = 0; $i < 7; $i++) { // 获取最近7天数据 $nowDay = $currentDate; if ($i > 0) { $nowDay = date("Y-m-d", strtotime("-" . $i . " day", strtotime($currentDate))); } $item = [ 'date' => date("m-d", strtotime($nowDay)), 'total_actives' => isset($censusMall[$nowDay]) ? $censusMall[$nowDay]['total_actives'] : 0, 'add_users' => isset($censusMall[$nowDay]) ? $censusMall[$nowDay]['add_users'] : 0, 'add_pay_users' => isset($censusMall[$nowDay]) ? $censusMall[$nowDay]['add_pay_people_nums'] : 0, ]; $saleTrendList[] = $item; } sort($saleTrendList); // 销售趋势 return compact('saleTrendList'); } public static function getSaleTrendByMonth(string $type = 'month') { // 获取销售额趋势(因为前端只有周和月所以默认获取前7个月订单) $currentMonth = date('Y-m', time()); $eventMonth = date('Y-m', strtotime("-7 month", strtotime($currentMonth))); $orderDetailGroupBy = 'year, month'; if ($type == 'week') { $orderDetailGroupBy = 'year, month, week'; } // 销售额(订单支付金额) 利润(总销售额-总成本) $orderDetailSql = "sum(goods_price) as goods_price, sum(goods_price - cost_price) as profit_price, YEAR(FROM_UNIXTIME(created_at)) as year, MONTH(FROM_UNIXTIME(created_at)) as month, WEEK(FROM_UNIXTIME(created_at)) as week"; $orderDetailModel = OrderDetail::find() ->where(['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]) ->andWhere(['!=', 'order_status', OrderStatusEnum::REPEAL]) ->andWhere(['>=', 'created_at', strtotime($eventMonth)]) ->select($orderDetailSql) ->asArray() ->groupBy($orderDetailGroupBy) ->orderBy('year desc, month desc') ->limit(6) ->all(); return compact('orderDetailModel'); } }