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

优化代码

This commit is contained in:
xiaochong0302 2020-09-12 19:57:28 +08:00
parent def5b3605a
commit d9016669e3
49 changed files with 470 additions and 276 deletions

View File

@ -15,7 +15,7 @@ abstract class Cache extends Component
public function __construct() public function __construct()
{ {
$this->cache = $this->getDI()->get('cache'); $this->cache = $this->getDI()->getShared('cache');
} }
/** /**

View File

@ -20,7 +20,7 @@ abstract class Counter extends Component
public function __construct() public function __construct()
{ {
$this->cache = $this->getDI()->get('cache'); $this->cache = $this->getDI()->getShared('cache');
$this->redis = $this->cache->getRedis(); $this->redis = $this->cache->getRedis();
} }

View File

@ -9,7 +9,7 @@ class CleanSessionTask extends Task
{ {
$config = $this->getConfig(); $config = $this->getConfig();
$cache = $this->getCache(); $cache = $this->getCache();
$redis = $cache->getRedis(); $redis = $this->getRedis();
$redis->select($config->path('session.db')); $redis->select($config->path('session.db'));

View File

@ -14,7 +14,7 @@ class LiveNotifyTask extends Task
{ {
$cache = $this->getCache(); $cache = $this->getCache();
$redis = $cache->getRedis(); $redis = $this->getRedis();
$service = new LiveNotifyService(); $service = new LiveNotifyService();

View File

@ -14,7 +14,7 @@ class SyncCourseIndexTask extends Task
{ {
$cache = $this->getCache(); $cache = $this->getCache();
$redis = $cache->getRedis(); $redis = $this->getRedis();
$key = $this->getSyncKey(); $key = $this->getSyncKey();

View File

@ -14,7 +14,7 @@ class SyncGroupIndexTask extends Task
{ {
$cache = $this->getCache(); $cache = $this->getCache();
$redis = $cache->getRedis(); $redis = $this->getRedis();
$key = $this->getSyncKey(); $key = $this->getSyncKey();

View File

@ -18,7 +18,7 @@ class SyncLearningTask extends Task
{ {
$cache = $this->getCache(); $cache = $this->getCache();
$redis = $cache->getRedis(); $redis = $this->getRedis();
$syncer = new LearningSyncer(); $syncer = new LearningSyncer();

View File

@ -14,7 +14,7 @@ class SyncUserIndexTask extends Task
{ {
$cache = $this->getCache(); $cache = $this->getCache();
$redis = $cache->getRedis(); $redis = $this->getRedis();
$key = $this->getSyncKey(); $key = $this->getSyncKey();

View File

@ -16,7 +16,7 @@ class Task extends \Phalcon\Cli\Task
*/ */
public function getConfig() public function getConfig()
{ {
return $this->getDI()->get('config'); return $this->getDI()->getShared('config');
} }
/** /**
@ -24,7 +24,15 @@ class Task extends \Phalcon\Cli\Task
*/ */
public function getCache() public function getCache()
{ {
return $this->getDI()->get('cache'); return $this->getDI()->getShared('cache');
}
/**
* @return \Redis
*/
public function getRedis()
{
return $this->getCache()->getRedis();
} }
/** /**

View File

@ -44,7 +44,7 @@ class UpgradeTask extends Task
{ {
$config = $this->getConfig(); $config = $this->getConfig();
$cache = $this->getCache(); $cache = $this->getCache();
$redis = $cache->getRedis(); $redis = $this->getRedis();
$dbIndex = $config->path('annotation.db'); $dbIndex = $config->path('annotation.db');
$statsKey = $config->path('annotation.statsKey'); $statsKey = $config->path('annotation.statsKey');
@ -75,7 +75,7 @@ class UpgradeTask extends Task
{ {
$config = $this->getConfig(); $config = $this->getConfig();
$cache = $this->getCache(); $cache = $this->getCache();
$redis = $cache->getRedis(); $redis = $this->getRedis();
$dbIndex = $config->path('metadata.db'); $dbIndex = $config->path('metadata.db');
$statsKey = $config->path('metadata.statsKey'); $statsKey = $config->path('metadata.statsKey');

View File

@ -27,8 +27,8 @@
<div class="layui-form-item"> <div class="layui-form-item">
<label class="layui-form-label">位置</label> <label class="layui-form-label">位置</label>
<div class="layui-input-block"> <div class="layui-input-block">
<input type="radio" name="position" value="top" title="顶部" {% if nav.position == 1 %}checked{% endif %}> <input type="radio" name="position" value="1" title="顶部" {% if nav.position == 1 %}checked{% endif %}>
<input type="radio" name="position" value="bottom" title="底部" {% if nav.position == 2 %}checked{% endif %}> <input type="radio" name="position" value="2" title="底部" {% if nav.position == 2 %}checked{% endif %}>
</div> </div>
</div> </div>
<div class="layui-form-item"> <div class="layui-form-item">

View File

@ -7,19 +7,19 @@
</div> </div>
</div> </div>
<div class="layui-form-item"> <div class="layui-form-item">
<label class="layui-form-label">App ID</label> <label class="layui-form-label">公众号ID</label>
<div class="layui-input-block"> <div class="layui-input-block">
<input class="layui-input" type="text" name="app_id" value="{{ wxpay.app_id }}" lay-verify="required"> <input class="layui-input" type="text" name="app_id" value="{{ wxpay.mp_app_id }}" lay-verify="required">
</div> </div>
</div> </div>
<div class="layui-form-item"> <div class="layui-form-item">
<label class="layui-form-label">Mch ID</label> <label class="layui-form-label">商户ID</label>
<div class="layui-input-block"> <div class="layui-input-block">
<input class="layui-input" type="text" name="mch_id" value="{{ wxpay.mch_id }}" lay-verify="required"> <input class="layui-input" type="text" name="mch_id" value="{{ wxpay.mch_id }}" lay-verify="required">
</div> </div>
</div> </div>
<div class="layui-form-item"> <div class="layui-form-item">
<label class="layui-form-label">Private Key</label> <label class="layui-form-label">支付Key</label>
<div class="layui-input-block"> <div class="layui-input-block">
<input class="layui-input" type="text" name="key" value="{{ wxpay.key }}" lay-verify="required"> <input class="layui-input" type="text" name="key" value="{{ wxpay.key }}" lay-verify="required">
</div> </div>

View File

@ -2,7 +2,8 @@
{% block content %} {% block content %}
{% set closed_tips_display = site.enabled == 0 ? 'display:block' : 'display:none' %} {% set closed_tips_display = site.status == 'closed' ? 'display:block' : 'display:none' %}
{% set analytics_script_display = site.analytics_enabled == 1 ? 'display:block' : 'display:none' %}
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.setting.site'}) }}"> <form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.setting.site'}) }}">
<fieldset class="layui-elem-field layui-field-title"> <fieldset class="layui-elem-field layui-field-title">
@ -11,8 +12,8 @@
<div class="layui-form-item"> <div class="layui-form-item">
<label class="layui-form-label">站点状态</label> <label class="layui-form-label">站点状态</label>
<div class="layui-input-block"> <div class="layui-input-block">
<input type="radio" name="enabled" value="1" title="正常" lay-filter="status" {% if site.enabled == 1 %}checked{% endif %}> <input type="radio" name="status" value="normal" title="正常" lay-filter="status" {% if site.status == 'normal' %}checked{% endif %}>
<input type="radio" name="enabled" value="0" title="关闭" lay-filter="status" {% if site.enabled == 0 %}checked{% endif %}> <input type="radio" name="status" value="closed" title="关闭" lay-filter="status" {% if site.status == 'closed' %}checked{% endif %}>
</div> </div>
</div> </div>
<div id="closed-tips-block" style="{{ closed_tips_display }}"> <div id="closed-tips-block" style="{{ closed_tips_display }}">
@ -89,9 +90,18 @@
</div> </div>
</div> </div>
<div class="layui-form-item"> <div class="layui-form-item">
<label class="layui-form-label">站点统计</label> <label class="layui-form-label">开启统计</label>
<div class="layui-input-block"> <div class="layui-input-block">
<textarea name="analytics" class="layui-textarea" placeholder="使用百度统计等第三方统计分析站点流量">{{ site.analytics }}</textarea> <input type="radio" name="analytics_enabled" value="1" title="是" lay-filter="analytics_enabled" {% if site.analytics_enabled == 1 %}checked{% endif %}>
<input type="radio" name="analytics_enabled" value="0" title="否" lay-filter="analytics_enabled" {% if site.analytics_enabled == 0 %}checked{% endif %}>
</div>
</div>
<div id="analytics-script-block" style="{{ analytics_script_display }}">
<div class="layui-form-item">
<label class="layui-form-label">统计代码</label>
<div class="layui-input-block">
<textarea name="analytics_script" class="layui-textarea" placeholder="使用百度统计等第三方统计分析站点流量">{{ site.analytics_script }}</textarea>
</div>
</div> </div>
</div> </div>
<div class="layui-form-item"> <div class="layui-form-item">
@ -117,7 +127,16 @@
form.on('radio(status)', function (data) { form.on('radio(status)', function (data) {
var block = $('#closed-tips-block'); var block = $('#closed-tips-block');
if (data.value === '0') { if (data.value === 'closed') {
block.show();
} else {
block.hide();
}
});
form.on('radio(analytics_enabled)', function (data) {
var block = $('#analytics-script-block');
if (data.value === '1') {
block.show(); block.show();
} else { } else {
block.hide(); block.hide();

View File

@ -2,6 +2,7 @@
namespace App\Http\Desktop\Controllers; namespace App\Http\Desktop\Controllers;
use App\Models\ChapterLive as LiveModel;
use App\Models\Course as CourseModel; use App\Models\Course as CourseModel;
use App\Services\Frontend\Chapter\ChapterInfo as ChapterInfoService; use App\Services\Frontend\Chapter\ChapterInfo as ChapterInfoService;
use App\Services\Frontend\Chapter\ChapterLike as ChapterLikeService; use App\Services\Frontend\Chapter\ChapterLike as ChapterLikeService;
@ -38,12 +39,21 @@ class ChapterController extends Controller
$catalog = $service->handle($chapter['course']['id']); $catalog = $service->handle($chapter['course']['id']);
$this->seo->prependTitle(['章节', $chapter['title'], $chapter['course']['title']]); $this->seo->prependTitle(['章节', $chapter['title'], $chapter['course']['title']]);
$this->seo->setDescription($chapter['summary']);
if (!empty($chapter['summary'])) {
$this->seo->setDescription($chapter['summary']);
}
if ($chapter['model'] == CourseModel::MODEL_VOD) { if ($chapter['model'] == CourseModel::MODEL_VOD) {
$this->view->pick('chapter/vod'); $this->view->pick('chapter/vod');
} elseif ($chapter['model'] == CourseModel::MODEL_LIVE) { } elseif ($chapter['model'] == CourseModel::MODEL_LIVE) {
$this->view->pick('chapter/live'); if ($chapter['status'] == LiveModel::STATUS_ACTIVE) {
$this->view->pick('chapter/live_active');
} elseif ($chapter['status'] == LiveModel::STATUS_INACTIVE) {
$this->view->pick('chapter/live_inactive');
} elseif ($chapter['status'] == LiveModel::STATUS_FORBID) {
$this->view->pick('chapter/live_forbid');
}
} elseif ($chapter['model'] == CourseModel::MODEL_READ) { } elseif ($chapter['model'] == CourseModel::MODEL_READ) {
$this->view->pick('chapter/read'); $this->view->pick('chapter/read');
} }

View File

@ -60,7 +60,11 @@ class Controller extends \Phalcon\Mvc\Controller
$this->checkCsrfToken(); $this->checkCsrfToken();
} }
$this->checkRateLimit(); $config = $this->getConfig();
if ($config->path('throttle.enabled')) {
$this->checkRateLimit();
}
return true; return true;
} }
@ -149,7 +153,7 @@ class Controller extends \Phalcon\Mvc\Controller
protected function checkSiteStatus() protected function checkSiteStatus()
{ {
if ($this->siteInfo['enabled'] == 0) { if ($this->siteInfo['status'] == 'closed') {
$this->dispatcher->forward([ $this->dispatcher->forward([
'controller' => 'error', 'controller' => 'error',
'action' => 'maintain', 'action' => 'maintain',

View File

@ -54,6 +54,18 @@ class LiveController extends Controller
return $this->jsonSuccess($stats); return $this->jsonSuccess($stats);
} }
/**
* @Get("/{id:[0-9]+}/status", name="desktop.live.status")
*/
public function statusAction($id)
{
$service = new LiveService();
$status = $service->getStatus($id);
return $this->jsonSuccess(['status' => $status]);
}
/** /**
* @Post("/{id:[0-9]+}/user/bind", name="desktop.live.bind_user") * @Post("/{id:[0-9]+}/user/bind", name="desktop.live.bind_user")
*/ */

View File

@ -2,7 +2,6 @@
namespace App\Http\Desktop\Services; namespace App\Http\Desktop\Services;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Services\Frontend\ChapterTrait; use App\Services\Frontend\ChapterTrait;
use GatewayClient\Gateway; use GatewayClient\Gateway;
@ -32,6 +31,13 @@ class Live extends Service
return $result; return $result;
} }
public function getStatus($id)
{
$chapterLive = $this->checkChapterLive($id);
return $chapterLive->status;
}
public function getStats($id) public function getStats($id)
{ {
$chapter = $this->checkChapter($id); $chapter = $this->checkChapter($id);
@ -84,7 +90,7 @@ class Live extends Service
public function sendMessage($id) public function sendMessage($id)
{ {
$chapter = $this->checkChapterCache($id); $chapter = $this->checkChapter($id);
$user = $this->getLoginUser(); $user = $this->getLoginUser();
@ -114,7 +120,7 @@ class Live extends Service
$redis = $this->getRedis(); $redis = $this->getRedis();
$key = $this->getRedisListKey($id); $key = $this->getRecentChatKey($id);
$redis->lPush($key, $encodeMessage); $redis->lPush($key, $encodeMessage);
@ -125,11 +131,6 @@ class Live extends Service
return $message; return $message;
} }
protected function getGroupName($id)
{
return "live_{$id}";
}
protected function getRegisterAddress() protected function getRegisterAddress()
{ {
$config = $this->getConfig(); $config = $this->getConfig();
@ -139,17 +140,12 @@ class Live extends Service
protected function getRecentChatKey($id) protected function getRecentChatKey($id)
{ {
return "live_recent_chat:{$id}"; return "chapter_recent_chat:{$id}";
} }
protected function getRedis() protected function getGroupName($id)
{ {
/** return "chapter_{$id}";
* @var RedisCache $cache
*/
$cache = $this->getDI()->get('cache');
return $cache->getRedis();
} }
} }

View File

@ -2,79 +2,24 @@
{% block content %} {% block content %}
{% set full_chapter_url = full_url({'for':'desktop.chapter.show','id':chapter.id}) %} {% if chapter.status == 'active' %}
{% set course_url = url({'for':'desktop.course.show','id':chapter.course.id}) %} {{ partial('live/live_active') }}
{% set learning_url = url({'for':'desktop.chapter.learning','id':chapter.id}) %} {% elseif chapter.status == 'inactive' %}
{% set live_chats_url = url({'for':'desktop.live.chats','id':chapter.id}) %} {{ partial('live/live_inactive') }}
{% set live_stats_url = url({'for':'desktop.live.stats','id':chapter.id}) %} {% elseif chapter.status =='forbid' %}
{% set send_msg_url = url({'for':'desktop.live.send_msg','id':chapter.id}) %} {{ partial('live/live_forbid') }}
{% set bind_user_url = url({'for':'desktop.live.bind_user','id':chapter.id}) %} {% endif %}
{% set like_url = url({'for':'desktop.chapter.like','id':chapter.id}) %}
{% set qrcode_url = url({'for':'desktop.qrcode'},{'text':full_chapter_url}) %}
<div class="breadcrumb">
<span class="layui-breadcrumb">
<a href="{{ course_url }}"><i class="layui-icon layui-icon-return"></i> 返回课程</a>
<a><cite>{{ chapter.course.title }}</cite></a>
<a><cite>{{ chapter.title }}</cite></a>
</span>
<span class="share">
<a href="javascript:" title="点赞" data-url="{{ like_url }}"><i class="layui-icon layui-icon-praise icon-praise"></i><em class="like-count">{{ chapter.like_count }}</em></a>
<a href="javascript:" title="在线人数"><i class="layui-icon layui-icon-user"></i><em>0</em></a>
<a href="javascript:" title="分享到微信" data-url=""><i class="layui-icon layui-icon-login-wechat icon-wechat"></i></a>
<a href="javascript:" title="分享到QQ空间"><i class="layui-icon layui-icon-login-qq icon-qq"></i></a>
<a href="javascript:" title="分享到微博"><i class="layui-icon layui-icon-login-weibo icon-weibo"></i></a>
</span>
</div>
<div class="layout-main">
<div class="layout-content">
<div class="player-wrap wrap">
<div id="player"></div>
</div>
</div>
<div class="layout-sidebar">
<div class="layui-card chat-wrap">
<div class="layui-card-header">直播讨论</div>
<div class="layui-card-body">
<div class="chat-msg-list" id="chat-msg-list" data-url="{{ live_chats_url }}"></div>
<form class="layui-form chat-msg-form" method="post" action="{{ send_msg_url }}">
{% if auth_user.id > 0 %}
<input class="layui-input" type="text" name="content" maxlength="50" placeholder="快来一起互动吧" lay-verType="tips" lay-verify="required">
{% else %}
<input class="layui-input" type="text" placeholder="登录后才可以发言哦" readonly="readonly">
{% endif %}
<button class="layui-hide" type="submit" lay-submit="true" lay-filter="chat">发送</button>
</form>
</div>
</div>
</div>
</div>
<div class="layui-hide">
<input type="hidden" name="chapter.id" value="{{ chapter.id }}">
<input type="hidden" name="chapter.plan_id" value="{{ chapter.me.plan_id }}">
<input type="hidden" name="chapter.learning_url" value="{{ learning_url }}">
<input type="hidden" name="chapter.play_urls" value='{{ chapter.play_urls|json_encode }}'>
<input type="hidden" name="live_stats_url" value='{{ live_stats_url }}'>
<input type="hidden" name="bind_user_url" value='{{ bind_user_url }}'>
</div>
<div class="layui-hide">
<input type="hidden" name="share.title" value="{{ chapter.course.title }}">
<input type="hidden" name="share.pic" value="{{ chapter.course.cover }}">
<input type="hidden" name="share.url" value="{{ full_chapter_url }}">
<input type="hidden" name="share.qrcode" value="{{ qrcode_url }}">
</div>
{% endblock %} {% endblock %}
{% block include_js %} {% block include_js %}
{{ js_include('https://imgcache.qq.com/open/qcloud/video/vcplayer/TcPlayer-2.3.3.js', false) }} {% if chapter.status == 'active' %}
{{ js_include('desktop/js/chapter.live.player.js') }} {{ js_include('https://imgcache.qq.com/open/qcloud/video/vcplayer/TcPlayer-2.3.3.js', false) }}
{{ js_include('desktop/js/chapter.live.chat.js') }} {{ js_include('desktop/js/chapter.live.player.js') }}
{{ js_include('desktop/js/chapter.action.js') }} {{ js_include('desktop/js/chapter.live.chat.js') }}
{{ js_include('desktop/js/course.share.js') }} {{ js_include('desktop/js/chapter.action.js') }}
{{ js_include('desktop/js/course.share.js') }}
{% endif %}
{% endblock %} {% endblock %}

View File

@ -0,0 +1,80 @@
{% extends 'templates/main.volt' %}
{% block content %}
{% set full_chapter_url = full_url({'for':'desktop.chapter.show','id':chapter.id}) %}
{% set course_url = url({'for':'desktop.course.show','id':chapter.course.id}) %}
{% set learning_url = url({'for':'desktop.chapter.learning','id':chapter.id}) %}
{% set live_chats_url = url({'for':'desktop.live.chats','id':chapter.id}) %}
{% set live_stats_url = url({'for':'desktop.live.stats','id':chapter.id}) %}
{% set send_msg_url = url({'for':'desktop.live.send_msg','id':chapter.id}) %}
{% set bind_user_url = url({'for':'desktop.live.bind_user','id':chapter.id}) %}
{% set like_url = url({'for':'desktop.chapter.like','id':chapter.id}) %}
{% set qrcode_url = url({'for':'desktop.qrcode'},{'text':full_chapter_url}) %}
<div class="breadcrumb">
<span class="layui-breadcrumb">
<a href="{{ course_url }}"><i class="layui-icon layui-icon-return"></i> 返回课程</a>
<a><cite>{{ chapter.course.title }}</cite></a>
<a><cite>{{ chapter.title }}</cite></a>
</span>
<span class="share">
<a href="javascript:" title="点赞" data-url="{{ like_url }}"><i class="layui-icon layui-icon-praise icon-praise"></i><em class="like-count">{{ chapter.like_count }}</em></a>
<a href="javascript:" title="在线人数"><i class="layui-icon layui-icon-user"></i><em>0</em></a>
<a href="javascript:" title="分享到微信" data-url=""><i class="layui-icon layui-icon-login-wechat icon-wechat"></i></a>
<a href="javascript:" title="分享到QQ空间"><i class="layui-icon layui-icon-login-qq icon-qq"></i></a>
<a href="javascript:" title="分享到微博"><i class="layui-icon layui-icon-login-weibo icon-weibo"></i></a>
</span>
</div>
<div class="layout-main">
<div class="layout-content">
<div class="player-wrap wrap">
<div id="player"></div>
</div>
</div>
<div class="layout-sidebar">
<div class="layui-card chat-wrap">
<div class="layui-card-header">直播讨论</div>
<div class="layui-card-body">
<div class="chat-msg-list" id="chat-msg-list" data-url="{{ live_chats_url }}"></div>
<form class="layui-form chat-msg-form" method="post" action="{{ send_msg_url }}">
{% if auth_user.id > 0 %}
<input class="layui-input" type="text" name="content" maxlength="50" placeholder="快来一起互动吧" lay-verType="tips" lay-verify="required">
{% else %}
<input class="layui-input" type="text" placeholder="登录后才可以发言哦" readonly="readonly">
{% endif %}
<button class="layui-hide" type="submit" lay-submit="true" lay-filter="chat">发送</button>
</form>
</div>
</div>
</div>
</div>
<div class="layui-hide">
<input type="hidden" name="chapter.id" value="{{ chapter.id }}">
<input type="hidden" name="chapter.plan_id" value="{{ chapter.me.plan_id }}">
<input type="hidden" name="chapter.learning_url" value="{{ learning_url }}">
<input type="hidden" name="chapter.play_urls" value='{{ chapter.play_urls|json_encode }}'>
<input type="hidden" name="live_stats_url" value='{{ live_stats_url }}'>
<input type="hidden" name="bind_user_url" value='{{ bind_user_url }}'>
</div>
<div class="layui-hide">
<input type="hidden" name="share.title" value="{{ chapter.course.title }}">
<input type="hidden" name="share.pic" value="{{ chapter.course.cover }}">
<input type="hidden" name="share.url" value="{{ full_chapter_url }}">
<input type="hidden" name="share.qrcode" value="{{ qrcode_url }}">
</div>
{% endblock %}
{% block include_js %}
{{ js_include('https://imgcache.qq.com/open/qcloud/video/vcplayer/TcPlayer-2.3.3.js', false) }}
{{ js_include('desktop/js/chapter.live.player.js') }}
{{ js_include('desktop/js/chapter.live.chat.js') }}
{{ js_include('desktop/js/chapter.action.js') }}
{{ js_include('desktop/js/course.share.js') }}
{% endblock %}

View File

@ -0,0 +1,15 @@
{% extends 'templates/main.volt' %}
{% block content %}
{% set course_url = url({'for':'desktop.course.show','id':chapter.course.id}) %}
<div class="breadcrumb">
<span class="layui-breadcrumb">
<a href="{{ course_url }}"><i class="layui-icon layui-icon-return"></i> 返回课程</a>
<a><cite>{{ chapter.course.title }}</cite></a>
<a><cite>{{ chapter.title }}</cite></a>
</span>
</div>
{% endblock %}

View File

@ -0,0 +1,42 @@
{% extends 'templates/main.volt' %}
{% block content %}
{% set course_url = url({'for':'desktop.course.show','id':chapter.course.id}) %}
{% set live_status_url = url({'for':'desktop.live.status','id':chapter.id}) %}
{% set show_countdown = time() < chapter.start_time ? 1 : 0 %}
<div class="breadcrumb">
<span class="layui-breadcrumb">
<a href="{{ course_url }}"><i class="layui-icon layui-icon-return"></i> 返回课程</a>
<a><cite>{{ chapter.course.title }}</cite></a>
<a><cite>{{ chapter.title }}</cite></a>
</span>
</div>
{% if show_countdown == 1 %}
<div class="countdown">
<div class="icon"><i class="layui-icon layui-icon-time"></i></div>
<div class="timer"></div>
<div class="tips">开播倒计时开始啦,敬请关注!</div>
</div>
{% else %}
<div class="countdown">
<div class="icon"><i class="layui-icon layui-icon-face-surprised"></i></div>
<div class="tips">直播已结束,谢谢关注!</div>
</div>
{% endif %}
<div class="layui-hide">
<input type="hidden" name="live.status_url" value="{{ live_status_url }}">
<input type="hidden" name="countdown.end_time" value="{{ chapter.start_time }}">
<input type="hidden" name="countdown.server_time" value="{{ time() }}">
</div>
{% endblock %}
{% block include_js %}
{{ js_include('desktop/js/chapter.live.countdown.js') }}
{% endblock %}

View File

@ -36,8 +36,8 @@
{% block include_js %}{% endblock %} {% block include_js %}{% endblock %}
{% block inline_js %}{% endblock %} {% block inline_js %}{% endblock %}
{% if site_info.analytics %} {% if site_info.analytics_enabled == 1 %}
{{ site_info.analytics }} {{ site_info.analytics_script }}
{% endif %} {% endif %}
</body> </body>

View File

@ -4,6 +4,7 @@ use App\Caches\Setting as SettingCache;
use App\Library\Validators\Common as CommonValidator; use App\Library\Validators\Common as CommonValidator;
use App\Services\Storage as StorageService; use App\Services\Storage as StorageService;
use Koogua\Ip2Region\Searcher as Ip2RegionSearcher; use Koogua\Ip2Region\Searcher as Ip2RegionSearcher;
use Phalcon\Config;
use Phalcon\Di; use Phalcon\Di;
use Phalcon\Text; use Phalcon\Text;
@ -404,12 +405,15 @@ function kg_js_include($path, $local = true, $version = null)
*/ */
function kg_static_url($path, $local = true, $version = null) function kg_static_url($path, $local = true, $version = null)
{ {
/**
* @var Config $config
*/
$config = Di::getDefault()->getShared('config'); $config = Di::getDefault()->getShared('config');
$baseUri = rtrim($config->static_base_uri, '/'); $baseUri = rtrim($config->get('static_base_uri'), '/');
$path = ltrim($path, '/'); $path = ltrim($path, '/');
$url = $local ? $baseUri . '/' . $path : $path; $url = $local ? $baseUri . '/' . $path : $path;
$version = $version ? $version : $config->static_version; $version = $version ? $version : $config->get('static_version');
if ($version) { if ($version) {
$url .= '?v=' . $version; $url .= '?v=' . $version;

View File

@ -2,6 +2,7 @@
namespace App\Library; namespace App\Library;
use Phalcon\Config;
use Phalcon\Di; use Phalcon\Di;
use Phalcon\Logger as PhLogger; use Phalcon\Logger as PhLogger;
use Phalcon\Logger\Adapter\File as FileLogger; use Phalcon\Logger\Adapter\File as FileLogger;
@ -15,7 +16,10 @@ class Logger
*/ */
public function getInstance($channel = null) public function getInstance($channel = null)
{ {
$config = Di::getDefault()->get('config'); /**
* @var Config $config
*/
$config = Di::getDefault()->getShared('config');
$channel = $channel ? $channel : 'common'; $channel = $channel ? $channel : 'common';
@ -23,7 +27,7 @@ class Logger
$path = log_path($filename); $path = log_path($filename);
$level = $config->env != ENV_DEV ? $config->log->level : PhLogger::DEBUG; $level = $config->get('env') != ENV_DEV ? $config->path('log.level') : PhLogger::DEBUG;
$logger = new FileLogger($path); $logger = new FileLogger($path);

View File

@ -21,7 +21,7 @@ class Chapter extends Model
* 推流状态 * 推流状态
*/ */
const SS_ACTIVE = 'active'; // 活跃 const SS_ACTIVE = 'active'; // 活跃
const SS_INACTIVE = 'inactive'; // 非活跃 const SS_INACTIVE = 'inactive'; // 静默
const SS_FORBID = 'forbid'; // 禁播 const SS_FORBID = 'forbid'; // 禁播
/** /**

View File

@ -19,7 +19,7 @@ class Api extends AuthService
$config = $this->getConfig(); $config = $this->getConfig();
$expireTime = time() + $config->jwt->lifetime; $expireTime = time() + $config->path('jwt.lifetime');
$builder->expiresAt($expireTime); $builder->expiresAt($expireTime);
$builder->withClaim('user_id', $user->id); $builder->withClaim('user_id', $user->id);
@ -27,7 +27,7 @@ class Api extends AuthService
$singer = new JwtSingerSha256(); $singer = new JwtSingerSha256();
$key = new JwtSingerKey($config->jwt->key); $key = new JwtSingerKey($config->path('jwt.key'));
$token = $builder->getToken($singer, $key); $token = $builder->getToken($singer, $key);
@ -51,7 +51,7 @@ class Api extends AuthService
$token = $parser->parse($authToken); $token = $parser->parse($authToken);
$data = new JWTValidationData(time(), $config->jwt->leeway); $data = new JWTValidationData(time(), $config->path('jwt.leeway'));
if (!$token->validate($data)) { if (!$token->validate($data)) {
return null; return null;
@ -59,7 +59,7 @@ class Api extends AuthService
$singer = new JwtSingerSha256(); $singer = new JwtSingerSha256();
if (!$token->verify($singer, $config->jwt->key)) { if (!$token->verify($singer, $config->path('jwt.key'))) {
return null; return null;
} }
@ -76,9 +76,4 @@ class Api extends AuthService
return trim(str_ireplace('Bearer', '', $authorization)); return trim(str_ireplace('Bearer', '', $authorization));
} }
protected function getConfig()
{
return $this->getDI()->get('config');
}
} }

View File

@ -6,6 +6,7 @@ use App\Models\Chapter as ChapterModel;
use App\Models\Course as CourseModel; use App\Models\Course as CourseModel;
use App\Repos\Chapter as ChapterRepo; use App\Repos\Chapter as ChapterRepo;
use App\Services\ChapterVod as ChapterVodService; use App\Services\ChapterVod as ChapterVodService;
use App\Services\Frontend\ChapterLiveTrait;
use App\Services\Live as LiveService; use App\Services\Live as LiveService;
use WhichBrowser\Parser as BrowserParser; use WhichBrowser\Parser as BrowserParser;
@ -85,6 +86,7 @@ trait BasicInfoTrait
'play_urls' => $playUrls, 'play_urls' => $playUrls,
'start_time' => $live->start_time, 'start_time' => $live->start_time,
'end_time' => $live->end_time, 'end_time' => $live->end_time,
'status' => $live->status,
'user_count' => $chapter->user_count, 'user_count' => $chapter->user_count,
'like_count' => $chapter->like_count, 'like_count' => $chapter->like_count,
]; ];

View File

@ -1,6 +1,6 @@
<?php <?php
namespace App\Services\Frontend\Chapter; namespace App\Services\Frontend;
trait ChapterLiveTrait trait ChapterLiveTrait
{ {

View File

@ -26,6 +26,27 @@ trait ChapterTrait
*/ */
protected $chapterUser; protected $chapterUser;
public function checkChapterVod($id)
{
$validator = new ChapterValidator();
return $validator->checkChapterVod($id);
}
public function checkChapterLive($id)
{
$validator = new ChapterValidator();
return $validator->checkChapterLive($id);
}
public function checkChapterRead($id)
{
$validator = new ChapterValidator();
return $validator->checkChapterRead($id);
}
public function checkChapter($id) public function checkChapter($id)
{ {
$validator = new ChapterValidator(); $validator = new ChapterValidator();

View File

@ -2,7 +2,7 @@
namespace App\Services\Frontend\Teaching; namespace App\Services\Frontend\Teaching;
use App\Services\Frontend\Chapter\ChapterLiveTrait; use App\Services\Frontend\ChapterLiveTrait;
use App\Services\Frontend\ChapterTrait; use App\Services\Frontend\ChapterTrait;
use App\Services\Frontend\Service as FrontendService; use App\Services\Frontend\Service as FrontendService;
use App\Services\Live as LiveService; use App\Services\Live as LiveService;

View File

@ -2,7 +2,6 @@
namespace App\Services; namespace App\Services;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Models\Chapter as ChapterModel; use App\Models\Chapter as ChapterModel;
use App\Models\ChapterLive as ChapterLiveModel; use App\Models\ChapterLive as ChapterLiveModel;
use App\Repos\Chapter as ChapterRepo; use App\Repos\Chapter as ChapterRepo;
@ -129,12 +128,9 @@ class LiveNotify extends Service
protected function sendBeginNotify(ChapterModel $chapter) protected function sendBeginNotify(ChapterModel $chapter)
{ {
/** $cache = $this->getCache();
* @var RedisCache $cache
*/
$cache = $this->getDI()->get('cache');
$redis = $cache->getRedis(); $redis = $this->getRedis();
$key = $this->getNotifyKey(); $key = $this->getNotifyKey();

View File

@ -41,11 +41,11 @@ class AlipayGateway extends Service
*/ */
public function getInstance() public function getInstance()
{ {
$config = $this->getDI()->get('config'); $config = $this->getConfig();
$level = $config->env == ENV_DEV ? 'debug' : 'info'; $level = $config->get('env') == ENV_DEV ? 'debug' : 'info';
$payConfig = [ $options = [
'app_id' => $this->settings['app_id'], 'app_id' => $this->settings['app_id'],
'ali_public_key' => $this->settings['public_key'], 'ali_public_key' => $this->settings['public_key'],
'private_key' => $this->settings['private_key'], 'private_key' => $this->settings['private_key'],
@ -59,11 +59,11 @@ class AlipayGateway extends Service
], ],
]; ];
if ($config->env == ENV_DEV) { if ($config->get('env') == ENV_DEV) {
$payConfig['mode'] = 'dev'; $options['mode'] = 'dev';
} }
return Pay::alipay($payConfig); return Pay::alipay($options);
} }
} }

View File

@ -36,17 +36,19 @@ class WxpayGateway extends Service
*/ */
public function getInstance() public function getInstance()
{ {
$config = $this->getDI()->get('config'); $config = $this->getConfig();
$level = $config->env == ENV_DEV ? 'debug' : 'info'; $level = $config->get('env') == ENV_DEV ? 'debug' : 'info';
$payConfig = [ $options = [
'app_id' => $this->settings['app_id'], 'appid' => $this->settings['app_id'], // App AppId
'app_id' => $this->settings['mp_app_id'], // 公众号 AppId
'miniapp_id' => $this->settings['mini_app_id'], // 小程序 AppId
'mch_id' => $this->settings['mch_id'], 'mch_id' => $this->settings['mch_id'],
'key' => $this->settings['key'], 'key' => $this->settings['key'],
'notify_url' => $this->settings['notify_url'], 'notify_url' => $this->settings['notify_url'],
'cert_client' => '', 'cert_client' => config_path('wxpay/client_cert.pem'),
'cert_key' => '', 'cert_key' => config_path('wxpay/client_key.pem'),
'log' => [ 'log' => [
'file' => log_path('wxpay.log'), 'file' => log_path('wxpay.log'),
'level' => $level, 'level' => $level,
@ -55,11 +57,11 @@ class WxpayGateway extends Service
], ],
]; ];
if ($config->env == ENV_DEV) { if ($config->get('env') == ENV_DEV) {
$payConfig['mode'] = 'dev'; $options['mode'] = 'dev';
} }
return Pay::wechat($payConfig); return Pay::wechat($options);
} }
} }

View File

@ -20,7 +20,7 @@ class Service extends Component
*/ */
public function getConfig() public function getConfig()
{ {
return $this->getDI()->get('config'); return $this->getDI()->getShared('config');
} }
/** /**
@ -28,7 +28,15 @@ class Service extends Component
*/ */
public function getCache() public function getCache()
{ {
return $this->getDI()->get('cache'); return $this->getDI()->getShared('cache');
}
/**
* @return \Redis
*/
public function getRedis()
{
return $this->getCache()->getRedis();
} }
/** /**

View File

@ -2,42 +2,26 @@
namespace App\Services\Syncer; namespace App\Services\Syncer;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Services\Service; use App\Services\Service;
class CourseIndex extends Service class CourseIndex extends Service
{ {
/**
* @var RedisCache
*/
protected $cache;
/**
* @var \Redis
*/
protected $redis;
/** /**
* @var int * @var int
*/ */
protected $lifetime = 86400; protected $lifetime = 86400;
public function __construct()
{
$this->cache = $this->getDI()->get('cache');
$this->redis = $this->cache->getRedis();
}
public function addItem($courseId) public function addItem($courseId)
{ {
$redis = $this->getRedis();
$key = $this->getSyncKey(); $key = $this->getSyncKey();
$this->redis->sAdd($key, $courseId); $redis->sAdd($key, $courseId);
if ($this->redis->sCard($key) == 1) { if ($redis->sCard($key) == 1) {
$this->redis->expire($key, $this->lifetime); $redis->expire($key, $this->lifetime);
} }
} }

View File

@ -2,42 +2,26 @@
namespace App\Services\Syncer; namespace App\Services\Syncer;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Services\Service; use App\Services\Service;
class GroupIndex extends Service class GroupIndex extends Service
{ {
/**
* @var RedisCache
*/
protected $cache;
/**
* @var \Redis
*/
protected $redis;
/** /**
* @var int * @var int
*/ */
protected $lifetime = 86400; protected $lifetime = 86400;
public function __construct()
{
$this->cache = $this->getDI()->get('cache');
$this->redis = $this->cache->getRedis();
}
public function addItem($groupId) public function addItem($groupId)
{ {
$redis = $this->getRedis();
$key = $this->getSyncKey(); $key = $this->getSyncKey();
$this->redis->sAdd($key, $groupId); $redis->sAdd($key, $groupId);
if ($this->redis->sCard($key) == 1) { if ($redis->sCard($key) == 1) {
$this->redis->expire($key, $this->lifetime); $redis->expire($key, $this->lifetime);
} }
} }

View File

@ -2,7 +2,6 @@
namespace App\Services\Syncer; namespace App\Services\Syncer;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Models\Learning as LearningModel; use App\Models\Learning as LearningModel;
use App\Services\Service; use App\Services\Service;
use App\Traits\Client as ClientTrait; use App\Traits\Client as ClientTrait;
@ -12,40 +11,27 @@ class Learning extends Service
use ClientTrait; use ClientTrait;
/**
* @var RedisCache
*/
protected $cache;
/**
* @var \Redis
*/
protected $redis;
/** /**
* @var int * @var int
*/ */
protected $lifetime = 86400; protected $lifetime = 86400;
public function __construct()
{
$this->cache = $this->getDI()->get('cache');
$this->redis = $this->cache->getRedis();
}
/** /**
* @param LearningModel $learning * @param LearningModel $learning
* @param int $interval * @param int $interval
*/ */
public function addItem(LearningModel $learning, $interval = 10) public function addItem(LearningModel $learning, $interval = 10)
{ {
$cache = $this->getCache();
$redis = $this->getRedis();
$itemKey = $this->getItemKey($learning->request_id); $itemKey = $this->getItemKey($learning->request_id);
/** /**
* @var LearningModel $cacheLearning * @var LearningModel $cacheLearning
*/ */
$cacheLearning = $this->cache->get($itemKey); $cacheLearning = $cache->get($itemKey);
if (!$cacheLearning) { if (!$cacheLearning) {
@ -54,7 +40,7 @@ class Learning extends Service
$learning->duration = $interval; $learning->duration = $interval;
$learning->active_time = time(); $learning->active_time = time();
$this->cache->save($itemKey, $learning, $this->lifetime); $cache->save($itemKey, $learning, $this->lifetime);
} else { } else {
@ -62,15 +48,15 @@ class Learning extends Service
$cacheLearning->position = $learning->position; $cacheLearning->position = $learning->position;
$cacheLearning->active_time = time(); $cacheLearning->active_time = time();
$this->cache->save($itemKey, $cacheLearning, $this->lifetime); $cache->save($itemKey, $cacheLearning, $this->lifetime);
} }
$key = $this->getSyncKey(); $key = $this->getSyncKey();
$this->redis->sAdd($key, $learning->request_id); $redis->sAdd($key, $learning->request_id);
if ($this->redis->sCard($key) == 1) { if ($redis->sCard($key) == 1) {
$this->redis->expire($key, $this->lifetime); $redis->expire($key, $this->lifetime);
} }
} }

View File

@ -2,42 +2,26 @@
namespace App\Services\Syncer; namespace App\Services\Syncer;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Services\Service; use App\Services\Service;
class UserIndex extends Service class UserIndex extends Service
{ {
/**
* @var RedisCache
*/
protected $cache;
/**
* @var \Redis
*/
protected $redis;
/** /**
* @var int * @var int
*/ */
protected $lifetime = 86400; protected $lifetime = 86400;
public function __construct()
{
$this->cache = $this->getDI()->get('cache');
$this->redis = $this->cache->getRedis();
}
public function addItem($userId) public function addItem($userId)
{ {
$redis = $this->getRedis();
$key = $this->getSyncKey(); $key = $this->getSyncKey();
$this->redis->sAdd($key, $userId); $redis->sAdd($key, $userId);
if ($this->redis->sCard($key) == 1) { if ($redis->sCard($key) == 1) {
$this->redis->expire($key, $this->lifetime); $redis->expire($key, $this->lifetime);
} }
} }

View File

@ -2,23 +2,18 @@
namespace App\Services; namespace App\Services;
use Phalcon\Cache\Backend\Redis as RedisCache;
class Throttle extends Service class Throttle extends Service
{ {
public function checkRateLimit() public function checkRateLimit()
{ {
$config = $this->getDI()->get('config'); $config = $this->getConfig();
if ($config->throttle->enabled == false) { if ($config->path('throttle.enabled') == false) {
return true; return true;
} }
/** $cache = $this->getCache();
* @var RedisCache $cache
*/
$cache = $this->getDI()->get('cache');
$sign = $this->getRequestSignature(); $sign = $this->getRequestSignature();
@ -27,13 +22,13 @@ class Throttle extends Service
$rateLimit = $cache->get($cacheKey); $rateLimit = $cache->get($cacheKey);
if ($rateLimit) { if ($rateLimit) {
if ($rateLimit >= $config->throttle->rate_limit) { if ($rateLimit >= $config->path('throttle.rate_limit')) {
return false; return false;
} else { } else {
$cache->increment($cacheKey, 1); $cache->increment($cacheKey, 1);
} }
} else { } else {
$cache->save($cacheKey, 1, $config->throttle->lifetime); $cache->save($cacheKey, 1, $config->path('throttle.lifetime'));
} }
return true; return true;

View File

@ -15,7 +15,7 @@ class Verify extends Service
public function __construct() public function __construct()
{ {
$this->cache = $this->getDI()->get('cache'); $this->cache = $this->getCache();
} }
public function getSmsCode($phone, $lifetime = 300) public function getSmsCode($phone, $lifetime = 300)

View File

@ -43,6 +43,45 @@ class Chapter extends Validator
return $chapter; return $chapter;
} }
public function checkChapterVod($id)
{
$chapterRepo = new ChapterRepo();
$chapterVod = $chapterRepo->findChapterVod($id);
if (!$chapterVod) {
throw new BadRequestException('chapter.vod_not_found');
}
return $chapterVod;
}
public function checkChapterLive($id)
{
$chapterRepo = new ChapterRepo();
$chapterLive = $chapterRepo->findChapterLive($id);
if (!$chapterLive) {
throw new BadRequestException('chapter.live_not_found');
}
return $chapterLive;
}
public function checkChapterRead($id)
{
$chapterRepo = new ChapterRepo();
$chapterRead = $chapterRepo->findChapterRead($id);
if (!$chapterRead) {
throw new BadRequestException('chapter.read_not_found');
}
return $chapterRead;
}
public function checkChapter($id) public function checkChapter($id)
{ {
$chapterRepo = new ChapterRepo(); $chapterRepo = new ChapterRepo();

View File

@ -28,22 +28,19 @@ class ChapterLive extends Validator
public function checkTimeRange($startTime, $endTime) public function checkTimeRange($startTime, $endTime)
{ {
$startTimeStamp = strtotime($startTime); if ($startTime < time()) {
$endTimeStamp = strtotime($endTime);
if ($startTimeStamp < time()) {
throw new BadRequestException('chapter_live.start_lt_now'); throw new BadRequestException('chapter_live.start_lt_now');
} }
if ($endTimeStamp < time()) { if ($startTime < time()) {
throw new BadRequestException('chapter_live.end_lt_now'); throw new BadRequestException('chapter_live.end_lt_now');
} }
if ($startTimeStamp >= $endTimeStamp) { if ($startTime >= $endTime) {
throw new BadRequestException('chapter_live.start_gt_end'); throw new BadRequestException('chapter_live.start_gt_end');
} }
if ($endTimeStamp - $startTimeStamp > 3 * 3600) { if ($endTime - $startTime > 3 * 3600) {
throw new BadRequestException('chapter_live.time_too_long'); throw new BadRequestException('chapter_live.time_too_long');
} }
} }

View File

@ -12,7 +12,7 @@ define('ENV_PRO', 'pro');
*/ */
function root_path($path = '') function root_path($path = '')
{ {
return dirname(__DIR__) . ($path ? "/{$path}" : ''); return dirname(__DIR__) . trim_path($path);
} }
/** /**
@ -23,7 +23,7 @@ function root_path($path = '')
*/ */
function app_path($path = '') function app_path($path = '')
{ {
return root_path('app') . ($path ? "/{$path}" : ''); return root_path('app') . trim_path($path);
} }
/** /**
@ -34,7 +34,7 @@ function app_path($path = '')
*/ */
function bootstrap_path($path = '') function bootstrap_path($path = '')
{ {
return root_path('bootstrap') . ($path ? "/{$path}" : ''); return root_path('bootstrap') . trim_path($path);
} }
/** /**
@ -45,7 +45,7 @@ function bootstrap_path($path = '')
*/ */
function config_path($path = '') function config_path($path = '')
{ {
return root_path('config') . ($path ? "/{$path}" : ''); return root_path('config') . trim_path($path);
} }
/** /**
@ -56,7 +56,7 @@ function config_path($path = '')
*/ */
function storage_path($path = '') function storage_path($path = '')
{ {
return root_path('storage') . ($path ? "/{$path}" : ''); return root_path('storage') . trim_path($path);
} }
/** /**
@ -67,7 +67,7 @@ function storage_path($path = '')
*/ */
function vendor_path($path = '') function vendor_path($path = '')
{ {
return root_path('vendor') . ($path ? "/{$path}" : ''); return root_path('vendor') . trim_path($path);
} }
/** /**
@ -78,7 +78,7 @@ function vendor_path($path = '')
*/ */
function public_path($path = '') function public_path($path = '')
{ {
return root_path('public') . ($path ? "/{$path}" : ''); return root_path('public') . trim_path($path);
} }
/** /**
@ -89,7 +89,7 @@ function public_path($path = '')
*/ */
function cache_path($path = '') function cache_path($path = '')
{ {
return storage_path('cache') . ($path ? "/{$path}" : ''); return storage_path('cache') . trim_path($path);
} }
/** /**
@ -100,7 +100,7 @@ function cache_path($path = '')
*/ */
function log_path($path = '') function log_path($path = '')
{ {
return storage_path('log') . ($path ? "/{$path}" : ''); return storage_path('log') . trim_path($path);
} }
/** /**
@ -111,18 +111,20 @@ function log_path($path = '')
*/ */
function tmp_path($path = '') function tmp_path($path = '')
{ {
return storage_path('tmp') . ($path ? "/{$path}" : ''); return storage_path('tmp') . trim_path($path);
} }
/** /**
* Rtrim slash * Rtrim slash
* *
* @param string $str * @param string $path
* @return string * @return string
*/ */
function rtrim_slash($str) function trim_path($path)
{ {
return rtrim($str, '/'); $path = trim($path, '/');
return $path ? "/{$path}" : '';
} }
/** /**

2
config/alipay/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.gitignore
!.gitignore

View File

@ -1,2 +0,0 @@
*
!.gitignore

View File

@ -1,2 +0,0 @@
*
!.gitignore

2
config/wxpay/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.gitignore
!.gitignore

View File

@ -909,6 +909,34 @@ body {
color: #666; color: #666;
} }
.countdown {
color: #666;
margin-top: 50px;
text-align: center;
}
.countdown .icon {
margin-bottom: 10px;
}
.countdown .icon .layui-icon {
font-size: 150px;
}
.countdown .tips {
font-size: 18px;
margin: 20px 0;
}
.countdown .timer {
font-size: 32px;
}
.countdown .timer span {
color: green;
padding: 10px;
}
.player-wrap { .player-wrap {
position: relative; position: relative;
width: 760px; width: 760px;

View File

@ -0,0 +1,32 @@
layui.use(['jquery', 'util'], function () {
var $ = layui.jquery;
var util = layui.util;
var endTime = $('input[name="countdown.end_time"]').val();
var serverTime = $('input[name="countdown.server_time"]').val();
var liveStatusUrl = $('input[name="live.status_url"]').val();
util.countdown(1000 * parseInt(endTime), 1000 * parseInt(serverTime), function (date, serverTime, timer) {
var items = [
{date: date[0], label: '天'},
{date: date[1], label: '时'},
{date: date[2], label: '分'},
{date: date[3], label: '秒'}
];
var html = '';
layui.each(items, function (index, item) {
html += '<span>' + item.date + '</span>' + item.label;
});
$('.countdown > .timer').html(html);
});
setInterval(function () {
$.get(liveStatusUrl, function (res) {
if (res.status === 1) {
window.location.reload();
}
});
}, 30000);
});