mirror of
https://gitee.com/koogua/course-tencent-cloud.git
synced 2025-06-24 20:06:09 +08:00
parent
b987ddf083
commit
6cd3fb6d6c
98
app/Http/Admin/Controllers/StatController.php
Normal file
98
app/Http/Admin/Controllers/StatController.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Admin\Controllers;
|
||||
|
||||
use App\Http\Admin\Services\Stat as StatService;
|
||||
|
||||
/**
|
||||
* @RoutePrefix("/admin/stat")
|
||||
*/
|
||||
class StatController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @Get("/sales/hot", name="admin.stat.hot_sales")
|
||||
*/
|
||||
public function hotSalesAction()
|
||||
{
|
||||
$statService = new StatService();
|
||||
|
||||
$years = $statService->getYearOptions();
|
||||
$months = $statService->getMonthOptions();
|
||||
$items = $statService->hotSales();
|
||||
|
||||
$this->view->pick('stat/hot_sales');
|
||||
$this->view->setVar('years', $years);
|
||||
$this->view->setVar('months', $months);
|
||||
$this->view->setVar('items', $items);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/sales", name="admin.stat.sales")
|
||||
*/
|
||||
public function salesAction()
|
||||
{
|
||||
$statService = new StatService();
|
||||
|
||||
$years = $statService->getYearOptions();
|
||||
$months = $statService->getMonthOptions();
|
||||
$data = $statService->sales();
|
||||
|
||||
$this->view->pick('stat/sales');
|
||||
$this->view->setVar('years', $years);
|
||||
$this->view->setVar('months', $months);
|
||||
$this->view->setVar('data', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/refunds", name="admin.stat.refunds")
|
||||
*/
|
||||
public function refundsAction()
|
||||
{
|
||||
$statService = new StatService();
|
||||
|
||||
$years = $statService->getYearOptions();
|
||||
$months = $statService->getMonthOptions();
|
||||
$data = $statService->refunds();
|
||||
|
||||
$this->view->pick('stat/refunds');
|
||||
$this->view->setVar('years', $years);
|
||||
$this->view->setVar('months', $months);
|
||||
$this->view->setVar('data', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/users/registered", name="admin.stat.reg_users")
|
||||
*/
|
||||
public function registeredUsersAction()
|
||||
{
|
||||
$statService = new StatService();
|
||||
|
||||
$years = $statService->getYearOptions();
|
||||
$months = $statService->getMonthOptions();
|
||||
$data = $statService->registeredUsers();
|
||||
|
||||
$this->view->pick('stat/registered_users');
|
||||
$this->view->setVar('years', $years);
|
||||
$this->view->setVar('months', $months);
|
||||
$this->view->setVar('data', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/users/online", name="admin.stat.online_users")
|
||||
*/
|
||||
public function onlineUsersAction()
|
||||
{
|
||||
$statService = new StatService();
|
||||
|
||||
$years = $statService->getYearOptions();
|
||||
$months = $statService->getMonthOptions();
|
||||
$data = $statService->onlineUsers();
|
||||
|
||||
$this->view->pick('stat/online_users');
|
||||
$this->view->setVar('years', $years);
|
||||
$this->view->setVar('months', $months);
|
||||
$this->view->setVar('data', $data);
|
||||
}
|
||||
|
||||
}
|
@ -438,6 +438,43 @@ class AuthNode extends Service
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => '2-7',
|
||||
'title' => '数据统计',
|
||||
'type' => 'menu',
|
||||
'children' => [
|
||||
[
|
||||
'id' => '2-7-1',
|
||||
'title' => '热卖商品',
|
||||
'type' => 'menu',
|
||||
'route' => 'admin.stat.hot_sales',
|
||||
],
|
||||
[
|
||||
'id' => '2-7-2',
|
||||
'title' => '成交订单',
|
||||
'type' => 'menu',
|
||||
'route' => 'admin.stat.sales',
|
||||
],
|
||||
[
|
||||
'id' => '2-7-3',
|
||||
'title' => '售后退款',
|
||||
'type' => 'menu',
|
||||
'route' => 'admin.stat.refunds',
|
||||
],
|
||||
[
|
||||
'id' => '2-7-4',
|
||||
'title' => '注册用户',
|
||||
'type' => 'menu',
|
||||
'route' => 'admin.stat.reg_users',
|
||||
],
|
||||
[
|
||||
'id' => '2-7-5',
|
||||
'title' => '活跃用户',
|
||||
'type' => 'menu',
|
||||
'route' => 'admin.stat.online_users',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
405
app/Http/Admin/Services/Stat.php
Normal file
405
app/Http/Admin/Services/Stat.php
Normal file
@ -0,0 +1,405 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Admin\Services;
|
||||
|
||||
use App\Models\Order as OrderModel;
|
||||
use App\Repos\Stat as StatRepo;
|
||||
|
||||
class Stat extends Service
|
||||
{
|
||||
|
||||
public function hotSales()
|
||||
{
|
||||
$type = $this->request->getQuery('type', 'int', OrderModel::ITEM_COURSE);
|
||||
$year = $this->request->getQuery('year', 'int', date('Y'));
|
||||
$month = $this->request->getQuery('month', 'int', date('m'));
|
||||
|
||||
$prev = $this->getPrevMonth($year, $month);
|
||||
|
||||
return [
|
||||
[
|
||||
'title' => "{$year}-{$month}",
|
||||
'sales' => $this->handleHotSales($type, $year, $month),
|
||||
],
|
||||
[
|
||||
'title' => "{$prev['year']}-{$prev['month']}",
|
||||
'sales' => $this->handleHotSales($type, $prev['year'], $prev['month']),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function sales()
|
||||
{
|
||||
$year = $this->request->getQuery('year', 'int', date('Y'));
|
||||
$month = $this->request->getQuery('month', 'int', date('m'));
|
||||
|
||||
$prev = $this->getPrevMonth($year, $month);
|
||||
$currSales = $this->handleSales($year, $month);
|
||||
$prevSales = $this->handleSales($prev['year'], $prev['month']);
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach (range(1, 31) as $day) {
|
||||
$date = sprintf('%02d', $day);
|
||||
$prevMonth = "{$prev['year']}-{$prev['month']}";
|
||||
$currMonth = "{$year}-{$month}";
|
||||
$items[] = [
|
||||
'date' => $date,
|
||||
$currMonth => $currSales[$date] ?? 0,
|
||||
$prevMonth => $prevSales[$date] ?? 0,
|
||||
];
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
public function refunds()
|
||||
{
|
||||
$year = $this->request->getQuery('year', 'int', date('Y'));
|
||||
$month = $this->request->getQuery('month', 'int', date('m'));
|
||||
|
||||
$prev = $this->getPrevMonth($year, $month);
|
||||
$currRefunds = $this->handleRefunds($year, $month);
|
||||
$prevRefunds = $this->handleRefunds($prev['year'], $prev['month']);
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach (range(1, 31) as $day) {
|
||||
$date = sprintf('%02d', $day);
|
||||
$prevMonth = "{$prev['year']}-{$prev['month']}";
|
||||
$currMonth = "{$year}-{$month}";
|
||||
$items[] = [
|
||||
'date' => $date,
|
||||
$currMonth => $currRefunds[$date] ?? 0,
|
||||
$prevMonth => $prevRefunds[$date] ?? 0,
|
||||
];
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
public function registeredUsers()
|
||||
{
|
||||
$year = $this->request->getQuery('year', 'int', date('Y'));
|
||||
$month = $this->request->getQuery('month', 'int', date('m'));
|
||||
|
||||
$prev = $this->getPrevMonth($year, $month);
|
||||
$currUsers = $this->handleRegisteredUsers($year, $month);
|
||||
$prevUsers = $this->handleRegisteredUsers($prev['year'], $prev['month']);
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach (range(1, 31) as $day) {
|
||||
$date = sprintf('%02d', $day);
|
||||
$prevMonth = "{$prev['year']}-{$prev['month']}";
|
||||
$currMonth = "{$year}-{$month}";
|
||||
$items[] = [
|
||||
'date' => $date,
|
||||
$currMonth => $currUsers[$date] ?? 0,
|
||||
$prevMonth => $prevUsers[$date] ?? 0,
|
||||
];
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
public function onlineUsers()
|
||||
{
|
||||
$year = $this->request->getQuery('year', 'int', date('Y'));
|
||||
$month = $this->request->getQuery('month', 'int', date('m'));
|
||||
|
||||
$prev = $this->getPrevMonth($year, $month);
|
||||
$currUsers = $this->handleOnlineUsers($year, $month);
|
||||
$prevUsers = $this->handleOnlineUsers($prev['year'], $prev['month']);
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach (range(1, 31) as $day) {
|
||||
$date = sprintf('%02d', $day);
|
||||
$prevMonth = "{$prev['year']}-{$prev['month']}";
|
||||
$currMonth = "{$year}-{$month}";
|
||||
$items[] = [
|
||||
'date' => $date,
|
||||
$currMonth => $currUsers[$date] ?? 0,
|
||||
$prevMonth => $prevUsers[$date] ?? 0,
|
||||
];
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
public function getYearOptions()
|
||||
{
|
||||
$end = date('Y');
|
||||
|
||||
$start = $end - 3;
|
||||
|
||||
return range($start, $end);
|
||||
}
|
||||
|
||||
public function getMonthOptions()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
foreach (range(1, 12) as $value) {
|
||||
$options[] = sprintf('%02d', $value);
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
protected function isCurrMonth($year, $month)
|
||||
{
|
||||
return date('Y-m') == "{$year}-{$month}";
|
||||
}
|
||||
|
||||
protected function getPrevMonth($year, $month)
|
||||
{
|
||||
$currentMonthTime = strtotime("{$year}-{$month}");
|
||||
|
||||
$prevMonthTime = strtotime('-1 month', $currentMonthTime);
|
||||
|
||||
return [
|
||||
'year' => date('Y', $prevMonthTime),
|
||||
'month' => date('m', $prevMonthTime),
|
||||
];
|
||||
}
|
||||
|
||||
protected function getMonthDates($year, $month)
|
||||
{
|
||||
$startTime = strtotime("{$year}-{$month}-01");
|
||||
|
||||
$days = date('t', $startTime);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach (range(1, $days) as $day) {
|
||||
$result[] = sprintf('%04d-%02d-%02d', $year, $month, $day);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function handleHotSales($type, $year, $month)
|
||||
{
|
||||
$keyName = "stat_hot_sales:{$type}_{$year}_{$month}";
|
||||
|
||||
$cache = $this->getCache();
|
||||
|
||||
$items = $cache->get($keyName);
|
||||
|
||||
if (!$items) {
|
||||
|
||||
$statRepo = new StatRepo();
|
||||
|
||||
$orders = $statRepo->findMonthlyOrders($type, $year, $month);
|
||||
|
||||
$items = [];
|
||||
|
||||
if ($orders->count() > 0) {
|
||||
|
||||
foreach ($orders as $order) {
|
||||
$key = $order->item_id;
|
||||
if (!isset($items[$key])) {
|
||||
$items[$key] = [
|
||||
'title' => $order->subject,
|
||||
'total_count' => 1,
|
||||
'total_amount' => $order->amount,
|
||||
];
|
||||
} else {
|
||||
$items[$key]['total_count'] += 1;
|
||||
$items[$key]['total_amount'] += $order->amount;
|
||||
}
|
||||
}
|
||||
|
||||
$totalCount = array_column($items, 'total_count');
|
||||
|
||||
array_multisort($totalCount, SORT_DESC, $items);
|
||||
}
|
||||
|
||||
$queryMonth = "{$year}-{$month}";
|
||||
|
||||
$currMonth = date('Y-m');
|
||||
|
||||
if ($queryMonth < $currMonth) {
|
||||
$cache->save($keyName, $items, 7 * 86400);
|
||||
} else {
|
||||
$cache->save($keyName, $items, 2 * 3600);
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
protected function handleSales($year, $month)
|
||||
{
|
||||
$keyName = "stat_sales:{$year}_{$month}";
|
||||
|
||||
$redis = $this->getRedis();
|
||||
|
||||
$list = $redis->hGetAll($keyName);
|
||||
|
||||
$statRepo = new StatRepo();
|
||||
|
||||
$currDate = date('Y-m-d');
|
||||
$currDay = date('d');
|
||||
|
||||
if (!$list) {
|
||||
$dates = $this->getMonthDates($year, $month);
|
||||
foreach ($dates as $date) {
|
||||
$key = substr($date, -2);
|
||||
if ($date < $currDate) {
|
||||
$list[$key] = $statRepo->sumDailySales($date);
|
||||
} elseif ($date == $currDate) {
|
||||
$list[$key] = -999;
|
||||
} else {
|
||||
$list[$key] = 0;
|
||||
}
|
||||
}
|
||||
$redis->hMSet($keyName, $list);
|
||||
$redis->expire($keyName, 7 * 86400);
|
||||
}
|
||||
|
||||
foreach ($list as $key => $value) {
|
||||
if ($value < 0) {
|
||||
$list[$key] = $statRepo->sumDailySales("{$year}-{$month}-{$key}");
|
||||
$redis->hSet($keyName, $key, $list[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isCurrMonth($year, $month)) {
|
||||
$list[$currDay] = $statRepo->sumDailySales($currDate);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
protected function handleRefunds($year, $month)
|
||||
{
|
||||
$keyName = "stat_refunds:{$year}_{$month}";
|
||||
|
||||
$redis = $this->getRedis();
|
||||
|
||||
$list = $redis->hGetAll($keyName);
|
||||
|
||||
$statRepo = new StatRepo();
|
||||
|
||||
$currDate = date('Y-m-d');
|
||||
$currDay = date('d');
|
||||
|
||||
if (!$list) {
|
||||
$dates = $this->getMonthDates($year, $month);
|
||||
foreach ($dates as $date) {
|
||||
$key = substr($date, -2);
|
||||
if ($date < $currDate) {
|
||||
$list[$key] = $statRepo->sumDailyRefunds($date);
|
||||
} elseif ($date == $currDate) {
|
||||
$list[$key] = -999;
|
||||
} else {
|
||||
$list[$key] = 0;
|
||||
}
|
||||
}
|
||||
$redis->hMSet($keyName, $list);
|
||||
$redis->expire($keyName, 7 * 86400);
|
||||
}
|
||||
|
||||
foreach ($list as $key => $value) {
|
||||
if ($value < 0) {
|
||||
$list[$key] = $statRepo->sumDailyRefunds("{$year}-{$month}-{$key}");
|
||||
$redis->hSet($keyName, $key, $list[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isCurrMonth($year, $month)) {
|
||||
$list[$currDay] = $statRepo->sumDailyRefunds($currDate);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
protected function handleRegisteredUsers($year, $month)
|
||||
{
|
||||
$keyName = "stat_reg_users:{$year}_{$month}";
|
||||
|
||||
$redis = $this->getRedis();
|
||||
|
||||
$list = $redis->hGetAll($keyName);
|
||||
|
||||
$statRepo = new StatRepo();
|
||||
|
||||
$currDate = date('Y-m-d');
|
||||
$currDay = date('d');
|
||||
|
||||
if (!$list) {
|
||||
$dates = $this->getMonthDates($year, $month);
|
||||
foreach ($dates as $date) {
|
||||
$key = substr($date, -2);
|
||||
if ($date < $currDate) {
|
||||
$list[$key] = $statRepo->countDailyRegisteredUser($date);
|
||||
} elseif ($date == $currDate) {
|
||||
$list[$key] = -999;
|
||||
} else {
|
||||
$list[$key] = 0;
|
||||
}
|
||||
}
|
||||
$redis->hMSet($keyName, $list);
|
||||
$redis->expire($keyName, 7 * 86400);
|
||||
}
|
||||
|
||||
foreach ($list as $key => $value) {
|
||||
if ($value < 0) {
|
||||
$list[$key] = $statRepo->countDailyRegisteredUser("{$year}-{$month}-{$key}");
|
||||
$redis->hSet($keyName, $key, $list[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isCurrMonth($year, $month)) {
|
||||
$list[$currDay] = $statRepo->countDailyRegisteredUser($currDate);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
protected function handleOnlineUsers($year, $month)
|
||||
{
|
||||
$keyName = "stat_online_users:{$year}_{$month}";
|
||||
|
||||
$redis = $this->getRedis();
|
||||
|
||||
$list = $redis->hGetAll($keyName);
|
||||
|
||||
$statRepo = new StatRepo();
|
||||
|
||||
$currDate = date('Y-m-d');
|
||||
$currDay = date('d');
|
||||
|
||||
if (!$list) {
|
||||
$dates = $this->getMonthDates($year, $month);
|
||||
foreach ($dates as $date) {
|
||||
$key = substr($date, -2);
|
||||
if ($date < $currDate) {
|
||||
$list[$key] = $statRepo->countDailyOnlineUser($date);
|
||||
} elseif ($date == $currDate) {
|
||||
$list[$key] = -999;
|
||||
} else {
|
||||
$list[$key] = 0;
|
||||
}
|
||||
}
|
||||
$redis->hMSet($keyName, $list);
|
||||
$redis->expire($keyName, 7 * 86400);
|
||||
}
|
||||
|
||||
foreach ($list as $key => $value) {
|
||||
if ($value < 0) {
|
||||
$list[$key] = $statRepo->countDailyOnlineUser("{$year}-{$month}-{$key}");
|
||||
$redis->hSet($keyName, $key, $list[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isCurrMonth($year, $month)) {
|
||||
$list[$currDay] = $statRepo->countDailyOnlineUser($currDate);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
}
|
101
app/Http/Admin/Views/stat/hot_sales.volt
Normal file
101
app/Http/Admin/Views/stat/hot_sales.volt
Normal file
@ -0,0 +1,101 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{%- macro show_sales(sales) %}
|
||||
<table class="layui-table kg-table">
|
||||
<colgroup>
|
||||
<col>
|
||||
<col>
|
||||
<col>
|
||||
<col>
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>排序</th>
|
||||
<th>名称</th>
|
||||
<th>数量</th>
|
||||
<th>金额</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for sale in sales %}
|
||||
<tr>
|
||||
<td>{{ loop.index }}</td>
|
||||
<td>{{ sale.title }}</td>
|
||||
<td>{{ sale.total_count }}</td>
|
||||
<td>{{ '¥%0.2f'|format(sale.total_amount) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{%- endmacro %}
|
||||
|
||||
{% set types = {'1':'课程','2':'套餐','3':'赞赏','4':'会员'} %}
|
||||
{% set year = request.get('year','int',date('Y')) %}
|
||||
{% set month = request.get('month','int',date('m')) %}
|
||||
{% set type = request.get('type','int',1) %}
|
||||
|
||||
<div class="kg-nav">
|
||||
<div class="kg-nav-left">
|
||||
<span class="layui-breadcrumb">
|
||||
<a><cite>热卖商品统计</cite></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form class="layui-form kg-search-form" method="GET" action="{{ url({'for':'admin.stat.hot_sales'}) }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">选择类型</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="type">
|
||||
{% for key,value in types %}
|
||||
<option value="{{ key }}" {% if key == type %}selected{% endif %}>{{ value }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<label class="layui-form-label">选择年份</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="year">
|
||||
{% for value in years %}
|
||||
<option value="{{ value }}" {% if value == year %}selected{% endif %}>{{ value }}年</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<label class="layui-form-label">选择月份</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="month">
|
||||
{% for value in months %}
|
||||
<option value="{{ value }}" {% if value == month %}selected{% endif %}>{{ value }}月</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-input-inline">
|
||||
<button class="layui-btn" lay-submit="true">查询</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="kg-sale-list layui-row layui-col-space15">
|
||||
{% for item in items %}
|
||||
<div class="layui-col-md6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">{{ item.title }}</div>
|
||||
<div class="layui-card-body">{{ show_sales(item.sales) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block inline_css %}
|
||||
|
||||
<style>
|
||||
.kg-sale-list {
|
||||
padding: 10px;
|
||||
background: #f2f2f2;
|
||||
}
|
||||
</style>
|
||||
|
||||
{% endblock %}
|
74
app/Http/Admin/Views/stat/online_users.volt
Normal file
74
app/Http/Admin/Views/stat/online_users.volt
Normal file
@ -0,0 +1,74 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% set year = request.get('year','int',date('Y')) %}
|
||||
{% set month = request.get('month','int',date('m')) %}
|
||||
|
||||
<div class="kg-nav">
|
||||
<div class="kg-nav-left">
|
||||
<span class="layui-breadcrumb">
|
||||
<a><cite>活跃用户统计</cite></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form class="layui-form kg-search-form" method="GET" action="{{ url({'for':'admin.stat.online_users'}) }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">选择年份</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="year">
|
||||
{% for value in years %}
|
||||
<option value="{{ value }}" {% if value == year %}selected{% endif %}>{{ value }}年</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<label class="layui-form-label">选择月份</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="month">
|
||||
{% for value in months %}
|
||||
<option value="{{ value }}" {% if value == month %}selected{% endif %}>{{ value }}月</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-input-inline">
|
||||
<button class="layui-btn" lay-submit="true">查询</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="kg-chart" id="chart"></div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
{{ js_include('https://cdn.bootcdn.net/ajax/libs/echarts/4.8.0/echarts.min.js', false) }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block inline_js %}
|
||||
|
||||
<script>
|
||||
|
||||
var myChart = echarts.init(document.getElementById('chart'));
|
||||
|
||||
var option = {
|
||||
legend: {},
|
||||
tooltip: {},
|
||||
dataset: {
|
||||
source: {{ data|json_encode }}
|
||||
},
|
||||
xAxis: {type: 'category'},
|
||||
yAxis: {},
|
||||
series: [
|
||||
{type: 'line'},
|
||||
{type: 'line'}
|
||||
]
|
||||
};
|
||||
|
||||
myChart.setOption(option);
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
74
app/Http/Admin/Views/stat/refunds.volt
Normal file
74
app/Http/Admin/Views/stat/refunds.volt
Normal file
@ -0,0 +1,74 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% set year = request.get('year','int',date('Y')) %}
|
||||
{% set month = request.get('month','int',date('m')) %}
|
||||
|
||||
<div class="kg-nav">
|
||||
<div class="kg-nav-left">
|
||||
<span class="layui-breadcrumb">
|
||||
<a><cite>售后退款统计</cite></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form class="layui-form kg-search-form" method="GET" action="{{ url({'for':'admin.stat.refunds'}) }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">选择年份</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="year">
|
||||
{% for value in years %}
|
||||
<option value="{{ value }}" {% if value == year %}selected{% endif %}>{{ value }}年</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<label class="layui-form-label">选择月份</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="month">
|
||||
{% for value in months %}
|
||||
<option value="{{ value }}" {% if value == month %}selected{% endif %}>{{ value }}月</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-input-inline">
|
||||
<button class="layui-btn" lay-submit="true">查询</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="kg-chart" id="chart"></div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
{{ js_include('https://cdn.bootcdn.net/ajax/libs/echarts/4.8.0/echarts.min.js', false) }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block inline_js %}
|
||||
|
||||
<script>
|
||||
|
||||
var myChart = echarts.init(document.getElementById('chart'));
|
||||
|
||||
var option = {
|
||||
legend: {},
|
||||
tooltip: {},
|
||||
dataset: {
|
||||
source: {{ data|json_encode }}
|
||||
},
|
||||
xAxis: {type: 'category'},
|
||||
yAxis: {},
|
||||
series: [
|
||||
{type: 'line'},
|
||||
{type: 'line'}
|
||||
]
|
||||
};
|
||||
|
||||
myChart.setOption(option);
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
74
app/Http/Admin/Views/stat/registered_users.volt
Normal file
74
app/Http/Admin/Views/stat/registered_users.volt
Normal file
@ -0,0 +1,74 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% set year = request.get('year','int',date('Y')) %}
|
||||
{% set month = request.get('month','int',date('m')) %}
|
||||
|
||||
<div class="kg-nav">
|
||||
<div class="kg-nav-left">
|
||||
<span class="layui-breadcrumb">
|
||||
<a><cite>注册用户统计</cite></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form class="layui-form kg-search-form" method="GET" action="{{ url({'for':'admin.stat.reg_users'}) }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">选择年份</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="year">
|
||||
{% for value in years %}
|
||||
<option value="{{ value }}" {% if value == year %}selected{% endif %}>{{ value }}年</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<label class="layui-form-label">选择月份</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="month">
|
||||
{% for value in months %}
|
||||
<option value="{{ value }}" {% if value == month %}selected{% endif %}>{{ value }}月</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-input-inline">
|
||||
<button class="layui-btn" lay-submit="true">查询</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="kg-chart" id="chart"></div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
{{ js_include('https://cdn.bootcdn.net/ajax/libs/echarts/4.8.0/echarts.min.js', false) }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block inline_js %}
|
||||
|
||||
<script>
|
||||
|
||||
var myChart = echarts.init(document.getElementById('chart'));
|
||||
|
||||
var option = {
|
||||
legend: {},
|
||||
tooltip: {},
|
||||
dataset: {
|
||||
source: {{ data|json_encode }}
|
||||
},
|
||||
xAxis: {type: 'category'},
|
||||
yAxis: {},
|
||||
series: [
|
||||
{type: 'line'},
|
||||
{type: 'line'}
|
||||
]
|
||||
};
|
||||
|
||||
myChart.setOption(option);
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
74
app/Http/Admin/Views/stat/sales.volt
Normal file
74
app/Http/Admin/Views/stat/sales.volt
Normal file
@ -0,0 +1,74 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% set year = request.get('year','int',date('Y')) %}
|
||||
{% set month = request.get('month','int',date('m')) %}
|
||||
|
||||
<div class="kg-nav">
|
||||
<div class="kg-nav-left">
|
||||
<span class="layui-breadcrumb">
|
||||
<a><cite>成交订单统计</cite></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form class="layui-form kg-search-form" method="GET" action="{{ url({'for':'admin.stat.sales'}) }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">选择年份</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="year">
|
||||
{% for value in years %}
|
||||
<option value="{{ value }}" {% if value == year %}selected{% endif %}>{{ value }}年</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<label class="layui-form-label">选择月份</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="month">
|
||||
{% for value in months %}
|
||||
<option value="{{ value }}" {% if value == month %}selected{% endif %}>{{ value }}月</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-input-inline">
|
||||
<button class="layui-btn" lay-submit="true">查询</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="kg-chart" id="chart"></div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
{{ js_include('https://cdn.bootcdn.net/ajax/libs/echarts/4.8.0/echarts.min.js', false) }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block inline_js %}
|
||||
|
||||
<script>
|
||||
|
||||
var myChart = echarts.init(document.getElementById('chart'));
|
||||
|
||||
var option = {
|
||||
legend: {},
|
||||
tooltip: {},
|
||||
dataset: {
|
||||
source: {{ data|json_encode }}
|
||||
},
|
||||
xAxis: {type: 'category'},
|
||||
yAxis: {},
|
||||
series: [
|
||||
{type: 'line'},
|
||||
{type: 'line'}
|
||||
]
|
||||
};
|
||||
|
||||
myChart.setOption(option);
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
52
app/Listeners/User.php
Normal file
52
app/Listeners/User.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Models\Online as OnlineModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\Online as OnlineRepo;
|
||||
use App\Traits\Client as ClientTrait;
|
||||
use Phalcon\Events\Event;
|
||||
|
||||
class User extends Listener
|
||||
{
|
||||
|
||||
use ClientTrait;
|
||||
|
||||
public function online(Event $event, $source, UserModel $user)
|
||||
{
|
||||
$now = time();
|
||||
|
||||
if ($now - $user->active_time > 600) {
|
||||
|
||||
$user->active_time = $now;
|
||||
|
||||
$user->update();
|
||||
|
||||
$onlineRepo = new OnlineRepo();
|
||||
|
||||
$online = $onlineRepo->findByUserDate($user->id, date('Y-m-d'));
|
||||
|
||||
if ($online) {
|
||||
|
||||
$online->active_time = $now;
|
||||
$online->client_type = $this->getClientType();
|
||||
$online->client_ip = $this->getClientIp();
|
||||
|
||||
$online->update();
|
||||
|
||||
} else {
|
||||
|
||||
$online = new OnlineModel();
|
||||
|
||||
$online->user_id = $user->id;
|
||||
$online->active_time = $now;
|
||||
$online->client_type = $this->getClientType();
|
||||
$online->client_ip = $this->getClientIp();
|
||||
|
||||
$online->create();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
79
app/Models/Online.php
Normal file
79
app/Models/Online.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
class Online extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* 主键编号
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $user_id;
|
||||
|
||||
/**
|
||||
* 计划编号
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $date;
|
||||
|
||||
/**
|
||||
* 客户端类型
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $client_type;
|
||||
|
||||
/**
|
||||
* 客户端IP
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $client_ip;
|
||||
|
||||
/**
|
||||
* 活跃时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $active_time;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $create_time;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $update_time;
|
||||
|
||||
public function getSource(): string
|
||||
{
|
||||
return 'kg_online';
|
||||
}
|
||||
|
||||
public function beforeCreate()
|
||||
{
|
||||
$this->create_time = time();
|
||||
}
|
||||
|
||||
public function beforeUpdate()
|
||||
{
|
||||
$this->update_time = time();
|
||||
}
|
||||
|
||||
}
|
@ -63,7 +63,7 @@ class Audit extends Repository
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param int $id
|
||||
* @return AuditModel|Model|bool
|
||||
*/
|
||||
public function findById($id)
|
||||
|
30
app/Repos/Online.php
Normal file
30
app/Repos/Online.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repos;
|
||||
|
||||
use App\Models\Online as OnlineModel;
|
||||
use Phalcon\Mvc\Model;
|
||||
|
||||
class Online extends Repository
|
||||
{
|
||||
|
||||
/**
|
||||
* @param int $userId
|
||||
* @param string $activeDate
|
||||
* @return OnlineModel|Model|bool
|
||||
*/
|
||||
public function findByUserDate($userId, $activeDate)
|
||||
{
|
||||
$activeTime = strtotime($activeDate);
|
||||
|
||||
return OnlineModel::findFirst([
|
||||
'conditions' => 'user_id = ?1 AND active_time BETWEEN ?2 AND ?3',
|
||||
'bind' => [
|
||||
1 => $userId,
|
||||
2 => $activeTime,
|
||||
3 => $activeTime + 86400,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
139
app/Repos/Stat.php
Normal file
139
app/Repos/Stat.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repos;
|
||||
|
||||
use App\Models\Online as OnlineModel;
|
||||
use App\Models\Order as OrderModel;
|
||||
use App\Models\OrderStatus as OrderStatusModel;
|
||||
use App\Models\Refund as RefundModel;
|
||||
use App\Models\User as UserModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class Stat extends Repository
|
||||
{
|
||||
|
||||
public function countDailyRegisteredUser($date)
|
||||
{
|
||||
$startTime = strtotime($date);
|
||||
|
||||
$endTime = $startTime + 86400;
|
||||
|
||||
return (int)UserModel::count([
|
||||
'conditions' => 'create_time BETWEEN :start_time: AND :end_time:',
|
||||
'bind' => ['start_time' => $startTime, 'end_time' => $endTime],
|
||||
]);
|
||||
}
|
||||
|
||||
public function countDailyOnlineUser($date)
|
||||
{
|
||||
$startTime = strtotime($date);
|
||||
|
||||
$endTime = $startTime + 86400;
|
||||
|
||||
return (int)OnlineModel::count([
|
||||
'conditions' => 'active_time BETWEEN :start_time: AND :end_time:',
|
||||
'bind' => ['start_time' => $startTime, 'end_time' => $endTime],
|
||||
]);
|
||||
}
|
||||
|
||||
public function countDailySales($date)
|
||||
{
|
||||
$sql = "SELECT count(*) AS total_count FROM %s AS os JOIN %s AS o ON os.order_id = o.id ";
|
||||
|
||||
$sql .= "WHERE os.status = ?1 AND o.create_time BETWEEN ?2 AND ?3";
|
||||
|
||||
$phql = sprintf($sql, OrderStatusModel::class, OrderModel::class);
|
||||
|
||||
$startTime = strtotime($date);
|
||||
|
||||
$endTime = $startTime + 86400;
|
||||
|
||||
$result = $this->modelsManager->executeQuery($phql, [
|
||||
1 => OrderModel::STATUS_FINISHED,
|
||||
2 => $startTime,
|
||||
3 => $endTime,
|
||||
]);
|
||||
|
||||
return (float)$result[0]['total_count'];
|
||||
}
|
||||
|
||||
public function countDailyRefunds($date)
|
||||
{
|
||||
$startTime = strtotime($date);
|
||||
|
||||
$endTime = $startTime + 86400;
|
||||
|
||||
return (int)RefundModel::count([
|
||||
'conditions' => 'status = ?1 AND create_time BETWEEN ?2 AND ?3',
|
||||
'bind' => [
|
||||
1 => RefundModel::STATUS_FINISHED,
|
||||
2 => $startTime,
|
||||
3 => $endTime,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function sumDailySales($date)
|
||||
{
|
||||
$sql = "SELECT sum(o.amount) AS total_amount FROM %s AS os JOIN %s AS o ON os.order_id = o.id ";
|
||||
|
||||
$sql .= "WHERE os.status = ?1 AND o.create_time BETWEEN ?2 AND ?3";
|
||||
|
||||
$phql = sprintf($sql, OrderStatusModel::class, OrderModel::class);
|
||||
|
||||
$startTime = strtotime($date);
|
||||
|
||||
$endTime = $startTime + 86400;
|
||||
|
||||
$result = $this->modelsManager->executeQuery($phql, [
|
||||
1 => OrderModel::STATUS_FINISHED,
|
||||
2 => $startTime,
|
||||
3 => $endTime,
|
||||
]);
|
||||
|
||||
return (float)$result[0]['total_amount'];
|
||||
}
|
||||
|
||||
public function sumDailyRefunds($date)
|
||||
{
|
||||
$startTime = strtotime($date);
|
||||
|
||||
$endTime = $startTime + 86400;
|
||||
|
||||
return (float)RefundModel::sum([
|
||||
'column' => 'amount',
|
||||
'conditions' => 'status = ?1 AND create_time BETWEEN ?2 AND ?3',
|
||||
'bind' => [
|
||||
1 => RefundModel::STATUS_FINISHED,
|
||||
2 => $startTime,
|
||||
3 => $endTime,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $type
|
||||
* @param int $year
|
||||
* @param int $month
|
||||
* @return ResultsetInterface|Resultset|OrderModel[]
|
||||
*/
|
||||
public function findMonthlyOrders($type, $year, $month)
|
||||
{
|
||||
$startTime = strtotime("{$year}-{$month}");
|
||||
|
||||
$endTime = strtotime('+1 month', $startTime);
|
||||
|
||||
$status = OrderModel::STATUS_FINISHED;
|
||||
|
||||
return $this->modelsManager->createBuilder()
|
||||
->addFrom(OrderStatusModel::class, 'os')
|
||||
->join(OrderModel::class, 'os.order_id = o.id', 'o')
|
||||
->columns('o.*')
|
||||
->where('o.item_type = :type:', ['type' => $type])
|
||||
->andWhere('os.status = :status:', ['status' => $status])
|
||||
->betweenWhere('o.create_time', $startTime, $endTime)
|
||||
->getQuery()->execute();
|
||||
}
|
||||
|
||||
}
|
@ -6,7 +6,8 @@ use App\Models\User as UserModel;
|
||||
use App\Repos\User as UserRepo;
|
||||
use App\Services\Auth as AuthService;
|
||||
use App\Validators\Validator as AppValidator;
|
||||
use Phalcon\Di;
|
||||
use Phalcon\Di as Di;
|
||||
use Phalcon\Events\Manager as EventsManager;
|
||||
|
||||
trait Auth
|
||||
{
|
||||
@ -24,7 +25,16 @@ trait Auth
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
return $userRepo->findById($authUser['id']);
|
||||
$user = $userRepo->findById($authUser['id']);
|
||||
|
||||
/**
|
||||
* @var EventsManager $eventsManager
|
||||
*/
|
||||
$eventsManager = Di::getDefault()->getShared('eventsManager');
|
||||
|
||||
$eventsManager->fire('user:online', $this, $user);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -40,13 +50,7 @@ trait Auth
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$user = $userRepo->findById($authUser['id']);
|
||||
|
||||
if (time() - $user->active_time > 600) {
|
||||
$user->update(['active_time' => time()]);
|
||||
}
|
||||
|
||||
return $user;
|
||||
return $userRepo->findById($authUser['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,9 +1,11 @@
|
||||
<?php
|
||||
|
||||
use App\Listeners\Pay;
|
||||
use App\Listeners\User;
|
||||
use App\Listeners\UserDailyCounter;
|
||||
|
||||
return [
|
||||
'pay' => Pay::class,
|
||||
'user' => User::class,
|
||||
'userDailyCounter' => UserDailyCounter::class,
|
||||
];
|
@ -2517,7 +2517,7 @@ class InitTable extends Phinx\Migration\AbstractMigration
|
||||
->addColumn('client_ip', 'string', [
|
||||
'null' => false,
|
||||
'default' => '',
|
||||
'limit' => 30,
|
||||
'limit' => 64,
|
||||
'collation' => 'utf8mb4_general_ci',
|
||||
'encoding' => 'utf8mb4',
|
||||
'comment' => '终端IP',
|
||||
|
107
db/migrations/20201004095647_create_online_table.php
Normal file
107
db/migrations/20201004095647_create_online_table.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
use Phinx\Db\Adapter\MysqlAdapter;
|
||||
|
||||
class CreateOnlineTable extends Phinx\Migration\AbstractMigration
|
||||
{
|
||||
public function change()
|
||||
{
|
||||
$this->table('kg_online', [
|
||||
'id' => false,
|
||||
'primary_key' => ['id'],
|
||||
'engine' => 'InnoDB',
|
||||
'encoding' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_general_ci',
|
||||
'comment' => '',
|
||||
'row_format' => 'DYNAMIC',
|
||||
])
|
||||
->addColumn('id', 'integer', [
|
||||
'null' => false,
|
||||
'limit' => MysqlAdapter::INT_REGULAR,
|
||||
'identity' => 'enable',
|
||||
'comment' => '主键编号',
|
||||
])
|
||||
->addColumn('user_id', 'integer', [
|
||||
'null' => false,
|
||||
'default' => '0',
|
||||
'limit' => MysqlAdapter::INT_REGULAR,
|
||||
'comment' => '用户编号',
|
||||
'after' => 'id',
|
||||
])
|
||||
->addColumn('client_type', 'integer', [
|
||||
'null' => false,
|
||||
'default' => '1',
|
||||
'limit' => MysqlAdapter::INT_REGULAR,
|
||||
'comment' => '终端类型',
|
||||
'after' => 'user_id',
|
||||
])
|
||||
->addColumn('client_ip', 'string', [
|
||||
'null' => false,
|
||||
'default' => '',
|
||||
'limit' => 64,
|
||||
'collation' => 'utf8mb4_general_ci',
|
||||
'encoding' => 'utf8mb4',
|
||||
'comment' => '终端IP',
|
||||
'after' => 'client_type',
|
||||
])
|
||||
->addColumn('active_time', 'integer', [
|
||||
'null' => false,
|
||||
'default' => '0',
|
||||
'limit' => MysqlAdapter::INT_REGULAR,
|
||||
'comment' => '活跃时间',
|
||||
'after' => 'client_ip',
|
||||
])
|
||||
->addColumn('create_time', 'integer', [
|
||||
'null' => false,
|
||||
'default' => '0',
|
||||
'limit' => MysqlAdapter::INT_REGULAR,
|
||||
'comment' => '创建时间',
|
||||
'after' => 'active_time',
|
||||
])
|
||||
->addColumn('update_time', 'integer', [
|
||||
'null' => false,
|
||||
'default' => '0',
|
||||
'limit' => MysqlAdapter::INT_REGULAR,
|
||||
'comment' => '更新时间',
|
||||
'after' => 'create_time',
|
||||
])
|
||||
->addIndex(['active_time'], [
|
||||
'name' => 'active_time',
|
||||
'unique' => false,
|
||||
])
|
||||
->addIndex(['user_id'], [
|
||||
'name' => 'user_id',
|
||||
'unique' => false,
|
||||
])
|
||||
->create();
|
||||
$this->table('kg_task', [
|
||||
'id' => false,
|
||||
'primary_key' => ['id'],
|
||||
'engine' => 'InnoDB',
|
||||
'encoding' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_general_ci',
|
||||
'comment' => '',
|
||||
'row_format' => 'DYNAMIC',
|
||||
])
|
||||
->save();
|
||||
$this->table('kg_trade', [
|
||||
'id' => false,
|
||||
'primary_key' => ['id'],
|
||||
'engine' => 'InnoDB',
|
||||
'encoding' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_general_ci',
|
||||
'comment' => '',
|
||||
'row_format' => 'DYNAMIC',
|
||||
])
|
||||
->changeColumn('channel_sn', 'string', [
|
||||
'null' => false,
|
||||
'default' => '',
|
||||
'limit' => 64,
|
||||
'collation' => 'utf8mb4_general_ci',
|
||||
'encoding' => 'utf8mb4',
|
||||
'comment' => '平台序号',
|
||||
'after' => 'channel',
|
||||
])
|
||||
->save();
|
||||
}
|
||||
}
|
@ -8822,14 +8822,14 @@ return array(
|
||||
'COLUMN_DEFAULT' => '',
|
||||
'IS_NULLABLE' => 'NO',
|
||||
'DATA_TYPE' => 'varchar',
|
||||
'CHARACTER_MAXIMUM_LENGTH' => '30',
|
||||
'CHARACTER_OCTET_LENGTH' => '120',
|
||||
'CHARACTER_MAXIMUM_LENGTH' => '64',
|
||||
'CHARACTER_OCTET_LENGTH' => '256',
|
||||
'NUMERIC_PRECISION' => NULL,
|
||||
'NUMERIC_SCALE' => NULL,
|
||||
'DATETIME_PRECISION' => NULL,
|
||||
'CHARACTER_SET_NAME' => 'utf8mb4',
|
||||
'COLLATION_NAME' => 'utf8mb4_general_ci',
|
||||
'COLUMN_TYPE' => 'varchar(30)',
|
||||
'COLUMN_TYPE' => 'varchar(64)',
|
||||
'COLUMN_KEY' => '',
|
||||
'EXTRA' => '',
|
||||
'PRIVILEGES' => 'select,insert,update,references',
|
||||
@ -9514,6 +9514,247 @@ return array(
|
||||
),
|
||||
'foreign_keys' => NULL,
|
||||
),
|
||||
'kg_online' =>
|
||||
array(
|
||||
'table' =>
|
||||
array(
|
||||
'table_name' => 'kg_online',
|
||||
'engine' => 'InnoDB',
|
||||
'table_comment' => '',
|
||||
'table_collation' => 'utf8mb4_general_ci',
|
||||
'character_set_name' => 'utf8mb4',
|
||||
'row_format' => 'Dynamic',
|
||||
),
|
||||
'columns' =>
|
||||
array(
|
||||
'id' =>
|
||||
array(
|
||||
'TABLE_CATALOG' => 'def',
|
||||
'TABLE_NAME' => 'kg_online',
|
||||
'COLUMN_NAME' => 'id',
|
||||
'ORDINAL_POSITION' => '1',
|
||||
'COLUMN_DEFAULT' => NULL,
|
||||
'IS_NULLABLE' => 'NO',
|
||||
'DATA_TYPE' => 'int',
|
||||
'CHARACTER_MAXIMUM_LENGTH' => NULL,
|
||||
'CHARACTER_OCTET_LENGTH' => NULL,
|
||||
'NUMERIC_PRECISION' => '10',
|
||||
'NUMERIC_SCALE' => '0',
|
||||
'DATETIME_PRECISION' => NULL,
|
||||
'CHARACTER_SET_NAME' => NULL,
|
||||
'COLLATION_NAME' => NULL,
|
||||
'COLUMN_TYPE' => 'int',
|
||||
'COLUMN_KEY' => 'PRI',
|
||||
'EXTRA' => 'auto_increment',
|
||||
'PRIVILEGES' => 'select,insert,update,references',
|
||||
'COLUMN_COMMENT' => '主键编号',
|
||||
'GENERATION_EXPRESSION' => '',
|
||||
'SRS_ID' => NULL,
|
||||
),
|
||||
'user_id' =>
|
||||
array(
|
||||
'TABLE_CATALOG' => 'def',
|
||||
'TABLE_NAME' => 'kg_online',
|
||||
'COLUMN_NAME' => 'user_id',
|
||||
'ORDINAL_POSITION' => '2',
|
||||
'COLUMN_DEFAULT' => '0',
|
||||
'IS_NULLABLE' => 'NO',
|
||||
'DATA_TYPE' => 'int',
|
||||
'CHARACTER_MAXIMUM_LENGTH' => NULL,
|
||||
'CHARACTER_OCTET_LENGTH' => NULL,
|
||||
'NUMERIC_PRECISION' => '10',
|
||||
'NUMERIC_SCALE' => '0',
|
||||
'DATETIME_PRECISION' => NULL,
|
||||
'CHARACTER_SET_NAME' => NULL,
|
||||
'COLLATION_NAME' => NULL,
|
||||
'COLUMN_TYPE' => 'int unsigned',
|
||||
'COLUMN_KEY' => 'MUL',
|
||||
'EXTRA' => '',
|
||||
'PRIVILEGES' => 'select,insert,update,references',
|
||||
'COLUMN_COMMENT' => '用户编号',
|
||||
'GENERATION_EXPRESSION' => '',
|
||||
'SRS_ID' => NULL,
|
||||
),
|
||||
'client_type' =>
|
||||
array(
|
||||
'TABLE_CATALOG' => 'def',
|
||||
'TABLE_NAME' => 'kg_online',
|
||||
'COLUMN_NAME' => 'client_type',
|
||||
'ORDINAL_POSITION' => '3',
|
||||
'COLUMN_DEFAULT' => '1',
|
||||
'IS_NULLABLE' => 'NO',
|
||||
'DATA_TYPE' => 'int',
|
||||
'CHARACTER_MAXIMUM_LENGTH' => NULL,
|
||||
'CHARACTER_OCTET_LENGTH' => NULL,
|
||||
'NUMERIC_PRECISION' => '10',
|
||||
'NUMERIC_SCALE' => '0',
|
||||
'DATETIME_PRECISION' => NULL,
|
||||
'CHARACTER_SET_NAME' => NULL,
|
||||
'COLLATION_NAME' => NULL,
|
||||
'COLUMN_TYPE' => 'int unsigned',
|
||||
'COLUMN_KEY' => '',
|
||||
'EXTRA' => '',
|
||||
'PRIVILEGES' => 'select,insert,update,references',
|
||||
'COLUMN_COMMENT' => '终端类型',
|
||||
'GENERATION_EXPRESSION' => '',
|
||||
'SRS_ID' => NULL,
|
||||
),
|
||||
'client_ip' =>
|
||||
array(
|
||||
'TABLE_CATALOG' => 'def',
|
||||
'TABLE_NAME' => 'kg_online',
|
||||
'COLUMN_NAME' => 'client_ip',
|
||||
'ORDINAL_POSITION' => '4',
|
||||
'COLUMN_DEFAULT' => '',
|
||||
'IS_NULLABLE' => 'NO',
|
||||
'DATA_TYPE' => 'varchar',
|
||||
'CHARACTER_MAXIMUM_LENGTH' => '64',
|
||||
'CHARACTER_OCTET_LENGTH' => '256',
|
||||
'NUMERIC_PRECISION' => NULL,
|
||||
'NUMERIC_SCALE' => NULL,
|
||||
'DATETIME_PRECISION' => NULL,
|
||||
'CHARACTER_SET_NAME' => 'utf8mb4',
|
||||
'COLLATION_NAME' => 'utf8mb4_general_ci',
|
||||
'COLUMN_TYPE' => 'varchar(64)',
|
||||
'COLUMN_KEY' => '',
|
||||
'EXTRA' => '',
|
||||
'PRIVILEGES' => 'select,insert,update,references',
|
||||
'COLUMN_COMMENT' => '终端IP',
|
||||
'GENERATION_EXPRESSION' => '',
|
||||
'SRS_ID' => NULL,
|
||||
),
|
||||
'active_time' =>
|
||||
array(
|
||||
'TABLE_CATALOG' => 'def',
|
||||
'TABLE_NAME' => 'kg_online',
|
||||
'COLUMN_NAME' => 'active_time',
|
||||
'ORDINAL_POSITION' => '5',
|
||||
'COLUMN_DEFAULT' => '0',
|
||||
'IS_NULLABLE' => 'NO',
|
||||
'DATA_TYPE' => 'int',
|
||||
'CHARACTER_MAXIMUM_LENGTH' => NULL,
|
||||
'CHARACTER_OCTET_LENGTH' => NULL,
|
||||
'NUMERIC_PRECISION' => '10',
|
||||
'NUMERIC_SCALE' => '0',
|
||||
'DATETIME_PRECISION' => NULL,
|
||||
'CHARACTER_SET_NAME' => NULL,
|
||||
'COLLATION_NAME' => NULL,
|
||||
'COLUMN_TYPE' => 'int unsigned',
|
||||
'COLUMN_KEY' => 'MUL',
|
||||
'EXTRA' => '',
|
||||
'PRIVILEGES' => 'select,insert,update,references',
|
||||
'COLUMN_COMMENT' => '活跃时间',
|
||||
'GENERATION_EXPRESSION' => '',
|
||||
'SRS_ID' => NULL,
|
||||
),
|
||||
'create_time' =>
|
||||
array(
|
||||
'TABLE_CATALOG' => 'def',
|
||||
'TABLE_NAME' => 'kg_online',
|
||||
'COLUMN_NAME' => 'create_time',
|
||||
'ORDINAL_POSITION' => '6',
|
||||
'COLUMN_DEFAULT' => '0',
|
||||
'IS_NULLABLE' => 'NO',
|
||||
'DATA_TYPE' => 'int',
|
||||
'CHARACTER_MAXIMUM_LENGTH' => NULL,
|
||||
'CHARACTER_OCTET_LENGTH' => NULL,
|
||||
'NUMERIC_PRECISION' => '10',
|
||||
'NUMERIC_SCALE' => '0',
|
||||
'DATETIME_PRECISION' => NULL,
|
||||
'CHARACTER_SET_NAME' => NULL,
|
||||
'COLLATION_NAME' => NULL,
|
||||
'COLUMN_TYPE' => 'int unsigned',
|
||||
'COLUMN_KEY' => '',
|
||||
'EXTRA' => '',
|
||||
'PRIVILEGES' => 'select,insert,update,references',
|
||||
'COLUMN_COMMENT' => '创建时间',
|
||||
'GENERATION_EXPRESSION' => '',
|
||||
'SRS_ID' => NULL,
|
||||
),
|
||||
'update_time' =>
|
||||
array(
|
||||
'TABLE_CATALOG' => 'def',
|
||||
'TABLE_NAME' => 'kg_online',
|
||||
'COLUMN_NAME' => 'update_time',
|
||||
'ORDINAL_POSITION' => '7',
|
||||
'COLUMN_DEFAULT' => '0',
|
||||
'IS_NULLABLE' => 'NO',
|
||||
'DATA_TYPE' => 'int',
|
||||
'CHARACTER_MAXIMUM_LENGTH' => NULL,
|
||||
'CHARACTER_OCTET_LENGTH' => NULL,
|
||||
'NUMERIC_PRECISION' => '10',
|
||||
'NUMERIC_SCALE' => '0',
|
||||
'DATETIME_PRECISION' => NULL,
|
||||
'CHARACTER_SET_NAME' => NULL,
|
||||
'COLLATION_NAME' => NULL,
|
||||
'COLUMN_TYPE' => 'int unsigned',
|
||||
'COLUMN_KEY' => '',
|
||||
'EXTRA' => '',
|
||||
'PRIVILEGES' => 'select,insert,update,references',
|
||||
'COLUMN_COMMENT' => '更新时间',
|
||||
'GENERATION_EXPRESSION' => '',
|
||||
'SRS_ID' => NULL,
|
||||
),
|
||||
),
|
||||
'indexes' =>
|
||||
array(
|
||||
'active_time' =>
|
||||
array(
|
||||
1 =>
|
||||
array(
|
||||
'Table' => 'kg_online',
|
||||
'Non_unique' => '1',
|
||||
'Key_name' => 'active_time',
|
||||
'Seq_in_index' => '1',
|
||||
'Column_name' => 'active_time',
|
||||
'Collation' => 'A',
|
||||
'Sub_part' => NULL,
|
||||
'Packed' => NULL,
|
||||
'Null' => '',
|
||||
'Index_type' => 'BTREE',
|
||||
'Comment' => '',
|
||||
'Index_comment' => '',
|
||||
),
|
||||
),
|
||||
'PRIMARY' =>
|
||||
array(
|
||||
1 =>
|
||||
array(
|
||||
'Table' => 'kg_online',
|
||||
'Non_unique' => '0',
|
||||
'Key_name' => 'PRIMARY',
|
||||
'Seq_in_index' => '1',
|
||||
'Column_name' => 'id',
|
||||
'Collation' => 'A',
|
||||
'Sub_part' => NULL,
|
||||
'Packed' => NULL,
|
||||
'Null' => '',
|
||||
'Index_type' => 'BTREE',
|
||||
'Comment' => '',
|
||||
'Index_comment' => '',
|
||||
),
|
||||
),
|
||||
'user_id' =>
|
||||
array(
|
||||
1 =>
|
||||
array(
|
||||
'Table' => 'kg_online',
|
||||
'Non_unique' => '1',
|
||||
'Key_name' => 'user_id',
|
||||
'Seq_in_index' => '1',
|
||||
'Column_name' => 'user_id',
|
||||
'Collation' => 'A',
|
||||
'Sub_part' => NULL,
|
||||
'Packed' => NULL,
|
||||
'Null' => '',
|
||||
'Index_type' => 'BTREE',
|
||||
'Comment' => '',
|
||||
'Index_comment' => '',
|
||||
),
|
||||
),
|
||||
),
|
||||
'foreign_keys' => NULL,
|
||||
),
|
||||
'kg_order' =>
|
||||
array(
|
||||
'table' =>
|
||||
@ -9752,14 +9993,14 @@ return array(
|
||||
'COLUMN_DEFAULT' => '',
|
||||
'IS_NULLABLE' => 'NO',
|
||||
'DATA_TYPE' => 'varchar',
|
||||
'CHARACTER_MAXIMUM_LENGTH' => '30',
|
||||
'CHARACTER_OCTET_LENGTH' => '120',
|
||||
'CHARACTER_MAXIMUM_LENGTH' => '64',
|
||||
'CHARACTER_OCTET_LENGTH' => '256',
|
||||
'NUMERIC_PRECISION' => NULL,
|
||||
'NUMERIC_SCALE' => NULL,
|
||||
'DATETIME_PRECISION' => NULL,
|
||||
'CHARACTER_SET_NAME' => 'utf8mb4',
|
||||
'COLLATION_NAME' => 'utf8mb4_general_ci',
|
||||
'COLUMN_TYPE' => 'varchar(30)',
|
||||
'COLUMN_TYPE' => 'varchar(64)',
|
||||
'COLUMN_KEY' => '',
|
||||
'EXTRA' => '',
|
||||
'PRIVILEGES' => 'select,insert,update,references',
|
||||
@ -12811,7 +13052,7 @@ return array(
|
||||
'CHARACTER_SET_NAME' => NULL,
|
||||
'COLLATION_NAME' => NULL,
|
||||
'COLUMN_TYPE' => 'int',
|
||||
'COLUMN_KEY' => 'MUL',
|
||||
'COLUMN_KEY' => '',
|
||||
'EXTRA' => '',
|
||||
'PRIVILEGES' => 'select,insert,update,references',
|
||||
'COLUMN_COMMENT' => '',
|
||||
@ -13429,14 +13670,14 @@ return array(
|
||||
'COLUMN_DEFAULT' => '',
|
||||
'IS_NULLABLE' => 'NO',
|
||||
'DATA_TYPE' => 'varchar',
|
||||
'CHARACTER_MAXIMUM_LENGTH' => '32',
|
||||
'CHARACTER_OCTET_LENGTH' => '128',
|
||||
'CHARACTER_MAXIMUM_LENGTH' => '64',
|
||||
'CHARACTER_OCTET_LENGTH' => '256',
|
||||
'NUMERIC_PRECISION' => NULL,
|
||||
'NUMERIC_SCALE' => NULL,
|
||||
'DATETIME_PRECISION' => NULL,
|
||||
'CHARACTER_SET_NAME' => 'utf8mb4',
|
||||
'COLLATION_NAME' => 'utf8mb4_general_ci',
|
||||
'COLUMN_TYPE' => 'varchar(32)',
|
||||
'COLUMN_TYPE' => 'varchar(64)',
|
||||
'COLUMN_KEY' => '',
|
||||
'EXTRA' => '',
|
||||
'PRIVILEGES' => 'select,insert,update,references',
|
||||
|
@ -258,3 +258,20 @@ img.kg-qrcode {
|
||||
font-size: 20px;
|
||||
color: rgb(0, 150, 136);
|
||||
}
|
||||
|
||||
.kg-search-form {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.kg-search-form .layui-form-label {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.kg-search-form .layui-input-inline:last-child {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.kg-chart {
|
||||
width: 100%;
|
||||
height: 480px;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user