1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-06-24 20:06:09 +08:00

设计后台首页

This commit is contained in:
xiaochong0302 2020-08-21 20:55:50 +08:00
parent 33b24e65e7
commit 1ec9c6f612
17 changed files with 19422 additions and 1376 deletions

65
app/Caches/SaleTrend.php Normal file
View File

@ -0,0 +1,65 @@
<?php
namespace App\Caches;
use App\Models\Order as OrderModel;
use Phalcon\Mvc\Model\Resultset;
use Phalcon\Mvc\Model\ResultsetInterface;
class SaleTrend extends Cache
{
protected $lifetime = 2 * 3600;
public function getLifetime()
{
return $this->lifetime;
}
public function getKey($id = null)
{
return 'sale_trend';
}
public function getContent($id = null)
{
}
/**
* @param OrderModel[] $sales
* @param int $days
* @return array
*/
protected function handleSales($sales, $days = 7)
{
$result = [];
foreach (array_reverse(range(1, $days)) as $num) {
$date = date('Y-m-d', strtotime("-{$num} days"));
$result[$date] = 0;
}
foreach ($sales as $sale) {
$date = date('Y-m-d', $sale->create_time);
$result[$date] += $sale->amount;
}
return $result;
}
/**
* @param int $days
* @return ResultsetInterface|Resultset|OrderModel[]
*/
protected function findSales($days = 7)
{
$time = strtotime("-{$days} days");
return OrderModel::query()
->where('status = :status:', ['status' => OrderModel::STATUS_FINISHED])
->andWhere('create_time > :time:', ['time' => $time])
->execute();
}
}

52
app/Caches/SiteStat.php Normal file
View File

@ -0,0 +1,52 @@
<?php
namespace App\Caches;
use App\Repos\Consult as ConsultRepo;
use App\Repos\Course as CourseRepo;
use App\Repos\ImGroup as GroupRepo;
use App\Repos\Order as OrderRepo;
use App\Repos\Package as PackageRepo;
use App\Repos\Review as ReviewRepo;
use App\Repos\Topic as TopicRepo;
use App\Repos\User as UserRepo;
class SiteStat extends Cache
{
protected $lifetime = 2 * 3600;
public function getLifetime()
{
return $this->lifetime;
}
public function getKey($id = null)
{
return 'site_stat';
}
public function getContent($id = null)
{
$courseRepo = new CourseRepo();
$consultRepo = new ConsultRepo();
$groupRepo = new GroupRepo();
$orderRepo = new OrderRepo();
$packageRepo = new PackageRepo();
$reviewRepo = new ReviewRepo();
$topicRepo = new TopicRepo();
$userRepo = new UserRepo();
return [
'course_count' => $courseRepo->countCourses(),
'consult_count' => $consultRepo->countConsults(),
'group_count' => $groupRepo->countGroups(),
'order_count' => $orderRepo->countOrders(),
'package_count' => $packageRepo->countPackages(),
'review_count' => $reviewRepo->countReviews(),
'topic_count' => $topicRepo->countTopics(),
'user_count' => $userRepo->countUsers(),
];
}
}

View File

@ -3,7 +3,6 @@
namespace App\Http\Admin\Controllers;
use App\Http\Admin\Services\Index as IndexService;
use App\Library\AppInfo;
use Phalcon\Mvc\View;
/**
@ -21,8 +20,7 @@ class IndexController extends Controller
$topMenus = $indexService->getTopMenus();
$leftMenus = $indexService->getLeftMenus();
$appInfo = new AppInfo();
$appInfo = $indexService->getAppInfo();
$this->view->setRenderLevel(View::LEVEL_ACTION_VIEW);
$this->view->setVar('app_info', $appInfo);
@ -35,7 +33,15 @@ class IndexController extends Controller
*/
public function mainAction()
{
$indexService = new IndexService();
$statInfo = $indexService->getStatInfo();
$appInfo = $indexService->getAppInfo();
$serverInfo = $indexService->getServerInfo();
$this->view->setVar('stat_info', $statInfo);
$this->view->setVar('app_info', $appInfo);
$this->view->setVar('server_info', $serverInfo);
}
}

View File

@ -2,6 +2,10 @@
namespace App\Http\Admin\Services;
use App\Caches\SiteStat;
use App\Library\AppInfo;
use App\Library\Utils\ServerInfo;
class Index extends Service
{
@ -19,4 +23,25 @@ class Index extends Service
return $authMenu->getLeftMenus();
}
public function getAppInfo()
{
return new AppInfo();
}
public function getServerInfo()
{
return [
'cpu' => ServerInfo::cpu(),
'memory' => ServerInfo::memory(),
'disk' => ServerInfo::disk(),
];
}
public function getStatInfo()
{
$cache = new SiteStat();
return $cache->get();
}
}

View File

@ -59,8 +59,8 @@
<div class="layui-body">
<iframe name="content" style="width:100%;height:100%;border:0;" src="{{ url({'for':'admin.main'}) }}"></iframe>
</div>
<div class="layui-footer">
<span>Powered by <a href="{{ app_info.link }}" title="{{ app_info.name }}">{{ app_info.alias }} {{ app_info.version }}</a></span>
<div class="layui-copyright">
Powered by <a href="{{ app_info.link }}" title="{{ app_info.name }}">{{ app_info.alias }} {{ app_info.version }}</a>
</div>
</div>
</body>

View File

@ -2,4 +2,28 @@
{% block content %}
<div class="layui-fluid">
<div class="layui-row layui-col-space15">
<div class="layui-col-md8">
{{ partial('index/main_stat_info') }}
</div>
<div class="layui-col-md4">
{{ partial('index/main_app_info') }}
{{ partial('index/main_server_info') }}
{{ partial('index/main_team_info') }}
</div>
</div>
</div>
{% endblock %}
{% block inline_css %}
<style>
.kg-body {
padding: 15px 0;
background: #f2f2f2;
}
</style>
{% endblock %}

View File

@ -0,0 +1,28 @@
<div class="layui-card layui-text">
<div class="layui-card-header">应用信息</div>
<div class="layui-card-body">
<table class="layui-table">
<colgroup>
<col width="100">
<col>
</colgroup>
<tbody>
<tr>
<td>当前版本</td>
<td>{{ app_info.alias }} {{ app_info.version }}</td>
</tr>
<tr>
<td>系统框架</td>
<td><a href="https://gitee.com/koogua/cphalcon">Phalcon 3.4.5</a></td>
</tr>
<tr>
<td>获取渠道</td>
<td>
<a href="https://gitee.com/koogua/course-tencent-cloud" target="_blank">Gitee</a>&nbsp;
<a href="https://github.com/koogua/course-tencent-cloud" target="_blank">Github</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>

View File

@ -0,0 +1,25 @@
<div class="layui-card layui-text" xmlns="http://www.w3.org/1999/html">
<div class="layui-card-header">服务器信息</div>
<div class="layui-card-body">
<table class="layui-table">
<colgroup>
<col width="100">
<col>
</colgroup>
<tbody>
<tr>
<td>磁盘空间</td>
<td>{{ server_info.disk.total }} 已用 {{ server_info.disk.usage }} 使用率 {{ server_info.disk.percent }}%</td>
</tr>
<tr>
<td>内存空间</td>
<td>{{ server_info.memory.total }} 已用 {{ server_info.memory.usage }} 使用率 {{ server_info.memory.percent }}%</td>
</tr>
<tr>
<td>系统负载</td>
<td>{{ server_info.cpu[0] }} {{ server_info.cpu[1] }} {{ server_info.cpu[2] }}</td>
</tr>
</tbody>
</table>
</div>
</div>

View File

@ -0,0 +1,55 @@
<div class="layui-card kg-stats">
<div class="layui-card-header">数据统计</div>
<div class="layui-card-body">
<div class="layui-row layui-col-space10">
<div class="layui-col-md3">
<div class="kg-stat-card">
<div class="name">课程数</div>
<div class="count">{{ stat_info.course_count }}</div>
</div>
</div>
<div class="layui-col-md3">
<div class="kg-stat-card">
<div class="name">用户数</div>
<div class="count">{{ stat_info.user_count }}</div>
</div>
</div>
<div class="layui-col-md3">
<div class="kg-stat-card">
<div class="name">群组数</div>
<div class="count">{{ stat_info.group_count }}</div>
</div>
</div>
<div class="layui-col-md3">
<div class="kg-stat-card">
<div class="name">订单数</div>
<div class="count">{{ stat_info.order_count }}</div>
</div>
</div>
<div class="layui-col-md3">
<div class="kg-stat-card">
<div class="name">评价数</div>
<div class="count">{{ stat_info.review_count }}</div>
</div>
</div>
<div class="layui-col-md3">
<div class="kg-stat-card">
<div class="name">咨询数</div>
<div class="count">{{ stat_info.consult_count }}</div>
</div>
</div>
<div class="layui-col-md3">
<div class="kg-stat-card">
<div class="name">套餐数</div>
<div class="count">{{ stat_info.package_count }}</div>
</div>
</div>
<div class="layui-col-md3">
<div class="kg-stat-card">
<div class="name">专题数</div>
<div class="count">{{ stat_info.topic_count }}</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,25 @@
<div class="layui-card layui-text">
<div class="layui-card-header">开发团队</div>
<div class="layui-card-body">
<table class="layui-table">
<colgroup>
<col width="100">
<col>
</colgroup>
<tbody>
<tr>
<td>版权所有</td>
<td><a href="http://koogua.com">深圳市酷瓜软件有限公司</a></td>
</tr>
<tr>
<td>项目经理</td>
<td>小虫哥哥</td>
</tr>
<tr>
<td>开发人员</td>
<td>小虫哥哥</td>
</tr>
</tbody>
</table>
</div>
</div>

View File

@ -0,0 +1,73 @@
<?php
namespace App\Library\Utils;
class ServerInfo
{
static function disk($dir = '/')
{
$free = disk_free_space($dir);
$total = disk_total_space($dir);
$usage = $total - $free;
$percent = 100 * $usage / $total;
return [
'total' => self::size($total),
'free' => self::size($free),
'usage' => self::size($usage),
'percent' => round($percent),
];
}
static function memory()
{
$mem = file_get_contents('/proc/meminfo');
$total = 0;
if (preg_match('/MemTotal\:\s+(\d+) kB/', $mem, $matches)) {
$total = $matches[1];
}
unset($matches);
$free = 0;
if (preg_match('/MemFree\:\s+(\d+) kB/', $mem, $matches)) {
$free = $matches[1];
}
$usage = $total - $free;
$percent = 100 * $usage / $total;
return array(
'total' => self::size($total * 1024),
'free' => self::size($free * 1024),
'usage' => self::size($usage * 1024),
'percent' => round($percent),
);
}
static function cpu()
{
$load = sys_getloadavg();
return array_map(function ($value) {
return sprintf('%.2f', $value);
}, $load);
}
static function size($bytes)
{
if (!$bytes) return 0;
$symbols = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
$exp = floor(log($bytes) / log(1024));
return sprintf('%.2f ' . $symbols[$exp], ($bytes / pow(1024, floor($exp))));
}
}

View File

@ -92,6 +92,11 @@ class Package extends Repository
->execute();
}
public function countPackages()
{
return (int)PackageModel::count(['conditions' => 'deleted = 0']);
}
public function countCourses($packageId)
{
return (int)CoursePackageModel::count([

View File

@ -125,7 +125,7 @@ class User extends Repository
public function countUsers()
{
return (int)UserModel::count();
return (int)UserModel::count(['conditions' => 'deleted = 0']);
}
public function countCourses($userId)

View File

@ -10,7 +10,6 @@
"swiftmailer/swiftmailer": "^6.0",
"peppeocchi/php-cron-scheduler": "^2.4",
"yansongda/pay": "^2.8",
"yansongda/supports": "^2.0",
"tencentcloud/tencentcloud-sdk-php": "3.*",
"qcloudsms/qcloudsms_php": "0.1.*",
"qcloud/cos-sdk-v5": "2.*",
@ -19,12 +18,13 @@
"whichbrowser/parser": "^2.0",
"hightman/xunsearch": "^1.4.14",
"aferrandini/phpqrcode": "1.0.1",
"xiaochong0302/ip2region": "^1.0"
"xiaochong0302/ip2region": "^1.0",
"robmorgan/phinx": "^0.12"
},
"require-dev": {
"odan/phinx-migrations-generator": "^4.6",
"phalcon/ide-stubs": "^3.4.3",
"jaeger/querylist": "^4.1"
"jaeger/querylist": "^4.1",
"odan/phinx-migrations-generator": "^5.1"
},
"repositories": {
"packagist": {

2808
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,25 @@
padding-bottom: 1px;
}
.layui-layout-admin .layui-body {
bottom: 0;
}
.layui-copyright {
position: fixed;
z-index: 999;
left: 0;
bottom: 0;
width: 180px;
padding: 10px;
font-size: 12px;
color: rgba(255, 255, 255, .7);
}
.layui-copyright a {
color: rgba(255, 255, 255, .7);
}
.kg-body {
padding: 15px;
}
@ -206,3 +225,19 @@ img.kg-qrcode {
padding-top: 0;
border-top: none;
}
.kg-stat-card {
padding: 10px 0;
text-align: center;
background: #f2f2f2;
}
.kg-stat-card .name {
margin-bottom: 5px;
color: #666;
}
.kg-stat-card .count {
font-size: 20px;
color: rgb(0, 150, 136);
}

File diff suppressed because it is too large Load Diff