mirror of
https://gitee.com/koogua/course-tencent-cloud.git
synced 2025-06-18 10:08:24 +08:00
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
247050f4ef | ||
|
57409cb630 | ||
|
4e1e8340b9 | ||
|
2ab6ae71cd | ||
|
303442f446 | ||
|
7281029dd0 | ||
|
f5ed2ce239 | ||
|
2a1b4b69fd | ||
|
123e1ec97f | ||
|
b2f795eb3b | ||
|
12db90d9c1 | ||
|
59bfe4a765 | ||
|
fb0b760e2e | ||
|
e31b86580d | ||
|
f2a446a876 | ||
|
27440fe679 | ||
|
7a9fee5545 | ||
|
d927e619e8 |
15
CHANGELOG.md
15
CHANGELOG.md
@ -1,3 +1,18 @@
|
|||||||
|
### [v1.7.8](https://gitee.com/koogua/course-tencent-cloud/releases/v1.7.8)(2025-06-20)
|
||||||
|
|
||||||
|
- 移除ThrottleLimit
|
||||||
|
- 增加CloseLiveTask
|
||||||
|
- 增加搜索页图片alt属性striptags过滤
|
||||||
|
- 后台增加返回顶部快捷方式
|
||||||
|
- 前台fixbar增加联系电话
|
||||||
|
- 优化安装脚本
|
||||||
|
- 优化课时列表直播提示
|
||||||
|
- 优化后台返回链接
|
||||||
|
- 优化统计分析代码位置
|
||||||
|
- 直播回调后更新课时缓存
|
||||||
|
- 后台清空头像->上传头像
|
||||||
|
- sitemap.xml直接写入网站根目录
|
||||||
|
|
||||||
### [v1.7.7](https://gitee.com/koogua/course-tencent-cloud/releases/v1.7.7)(2025-04-20)
|
### [v1.7.7](https://gitee.com/koogua/course-tencent-cloud/releases/v1.7.7)(2025-04-20)
|
||||||
|
|
||||||
- 优化索引管理工具
|
- 优化索引管理工具
|
||||||
|
@ -18,6 +18,13 @@ abstract class Migration
|
|||||||
|
|
||||||
abstract public function run();
|
abstract public function run();
|
||||||
|
|
||||||
|
protected function saveSettings(array $settings)
|
||||||
|
{
|
||||||
|
foreach ($settings as $setting) {
|
||||||
|
$this->saveSetting($setting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function saveSetting(array $setting)
|
protected function saveSetting(array $setting)
|
||||||
{
|
{
|
||||||
$settingRepo = new SettingRepo();
|
$settingRepo = new SettingRepo();
|
||||||
|
72
app/Console/Tasks/CloseLiveTask.php
Normal file
72
app/Console/Tasks/CloseLiveTask.php
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2024 深圳市酷瓜软件有限公司
|
||||||
|
* @license https://opensource.org/licenses/GPL-2.0
|
||||||
|
* @link https://www.koogua.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Console\Tasks;
|
||||||
|
|
||||||
|
use App\Caches\CourseChapterList as CourseChapterListCache;
|
||||||
|
use App\Models\Chapter as ChapterModel;
|
||||||
|
use App\Models\ChapterLive as ChapterLiveModel;
|
||||||
|
use App\Repos\Chapter as ChapterRepo;
|
||||||
|
use Phalcon\Mvc\Model\Resultset;
|
||||||
|
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||||
|
|
||||||
|
class CloseLiveTask extends Task
|
||||||
|
{
|
||||||
|
|
||||||
|
public function mainAction()
|
||||||
|
{
|
||||||
|
$chapterLives = $this->findChapterLives();
|
||||||
|
|
||||||
|
echo sprintf('pending lives: %s', $chapterLives->count()) . PHP_EOL;
|
||||||
|
|
||||||
|
if ($chapterLives->count() == 0) return;
|
||||||
|
|
||||||
|
echo '------ start close live task ------' . PHP_EOL;
|
||||||
|
|
||||||
|
foreach ($chapterLives as $chapterLive) {
|
||||||
|
|
||||||
|
$chapterLive->status = ChapterLiveModel::STATUS_INACTIVE;
|
||||||
|
|
||||||
|
$chapterLive->update();
|
||||||
|
|
||||||
|
$chapterRepo = new ChapterRepo();
|
||||||
|
|
||||||
|
$chapter = $chapterRepo->findById($chapterLive->chapter_id);
|
||||||
|
|
||||||
|
$attrs = $chapter->attrs;
|
||||||
|
$attrs['stream']['status'] = ChapterModel::SS_INACTIVE;
|
||||||
|
$chapter->attrs = $attrs;
|
||||||
|
|
||||||
|
$chapter->update();
|
||||||
|
|
||||||
|
$cache = new CourseChapterListCache();
|
||||||
|
|
||||||
|
$cache->rebuild($chapterLive->course_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '------ end close live task ------' . PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找待关闭直播
|
||||||
|
*
|
||||||
|
* @param int $limit
|
||||||
|
* @return ResultsetInterface|Resultset|ChapterLiveModel[]
|
||||||
|
*/
|
||||||
|
protected function findChapterLives(int $limit = 100)
|
||||||
|
{
|
||||||
|
$status = ChapterLiveModel::STATUS_ACTIVE;
|
||||||
|
$endTime = time() - 3600;
|
||||||
|
|
||||||
|
return ChapterLiveModel::query()
|
||||||
|
->where('status = :status:', ['status' => $status])
|
||||||
|
->andWhere('end_time < :end_time:', ['end_time' => $endTime])
|
||||||
|
->limit($limit)
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -37,7 +37,7 @@ class SitemapTask extends Task
|
|||||||
|
|
||||||
$this->sitemap = new Sitemap();
|
$this->sitemap = new Sitemap();
|
||||||
|
|
||||||
$filename = tmp_path('sitemap.xml');
|
$filename = public_path('sitemap.xml');
|
||||||
|
|
||||||
echo '------ start sitemap task ------' . PHP_EOL;
|
echo '------ start sitemap task ------' . PHP_EOL;
|
||||||
|
|
||||||
|
@ -13,12 +13,12 @@ use GuzzleHttp\Client;
|
|||||||
class SyncAppInfoTask extends Task
|
class SyncAppInfoTask extends Task
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const API_BASE_URL = 'https://www.koogua.com/api';
|
||||||
|
|
||||||
public function mainAction()
|
public function mainAction()
|
||||||
{
|
{
|
||||||
echo '------ start sync app info ------' . PHP_EOL;
|
echo '------ start sync app info ------' . PHP_EOL;
|
||||||
|
|
||||||
$url = 'https://www.koogua.com/api/instance/collect';
|
|
||||||
|
|
||||||
$site = $this->getSettings('site');
|
$site = $this->getSettings('site');
|
||||||
|
|
||||||
$serverHost = parse_url($site['url'], PHP_URL_HOST);
|
$serverHost = parse_url($site['url'], PHP_URL_HOST);
|
||||||
@ -38,6 +38,8 @@ class SyncAppInfoTask extends Task
|
|||||||
|
|
||||||
$client = new Client();
|
$client = new Client();
|
||||||
|
|
||||||
|
$url = sprintf('%s/instance/collect', self::API_BASE_URL);
|
||||||
|
|
||||||
$client->request('POST', $url, ['form_params' => $params]);
|
$client->request('POST', $url, ['form_params' => $params]);
|
||||||
|
|
||||||
echo '------ end sync app info ------' . PHP_EOL;
|
echo '------ end sync app info ------' . PHP_EOL;
|
||||||
|
@ -71,28 +71,6 @@ class UploadController extends Controller
|
|||||||
return $this->jsonSuccess(['data' => $data]);
|
return $this->jsonSuccess(['data' => $data]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Post("/avatar/img", name="admin.upload.avatar_img")
|
|
||||||
*/
|
|
||||||
public function uploadAvatarImageAction()
|
|
||||||
{
|
|
||||||
$service = new StorageService();
|
|
||||||
|
|
||||||
$file = $service->uploadAvatarImage();
|
|
||||||
|
|
||||||
if (!$file) {
|
|
||||||
return $this->jsonError(['msg' => '上传文件失败']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'id' => $file->id,
|
|
||||||
'name' => $file->name,
|
|
||||||
'url' => $service->getImageUrl($file->path),
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this->jsonSuccess(['data' => $data]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Post("/content/img", name="admin.upload.content_img")
|
* @Post("/content/img", name="admin.upload.content_img")
|
||||||
*/
|
*/
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<div class="kg-nav-left">
|
<div class="kg-nav-left">
|
||||||
<span class="layui-breadcrumb">
|
<span class="layui-breadcrumb">
|
||||||
{% if parent.id > 0 %}
|
{% if parent.id > 0 %}
|
||||||
<a class="kg-back" href="{{ back_url }}"><i class="layui-icon layui-icon-return"></i>返回</a>
|
<a href="{{ back_url }}"><i class="layui-icon layui-icon-return"></i>返回</a>
|
||||||
<a><cite>{{ parent.name }}</cite></a>
|
<a><cite>{{ parent.name }}</cite></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a><cite>分类管理</cite></a>
|
<a><cite>分类管理</cite></a>
|
||||||
|
@ -88,7 +88,7 @@
|
|||||||
layer.open({
|
layer.open({
|
||||||
type: 2,
|
type: 2,
|
||||||
title: '推流测试',
|
title: '推流测试',
|
||||||
area: ['720px', '500px'],
|
area: ['720px', '540px'],
|
||||||
content: [url, 'no']
|
content: [url, 'no']
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
<div class="kg-nav">
|
<div class="kg-nav">
|
||||||
<div class="kg-nav-left">
|
<div class="kg-nav-left">
|
||||||
<span class="layui-breadcrumb">
|
<span class="layui-breadcrumb">
|
||||||
<a class="kg-back" href="{{ back_url }}"><i class="layui-icon layui-icon-return"></i>返回</a>
|
<a href="{{ back_url }}"><i class="layui-icon layui-icon-return"></i>返回</a>
|
||||||
<a><cite>{{ course.title }}</cite></a>
|
<a><cite>{{ course.title }}</cite></a>
|
||||||
<a><cite>{{ chapter.title }}</cite></a>
|
<a><cite>{{ chapter.title }}</cite></a>
|
||||||
<a><cite>课时管理</cite></a>
|
<a><cite>课时管理</cite></a>
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<div class="kg-nav">
|
<div class="kg-nav">
|
||||||
<div class="kg-nav-left">
|
<div class="kg-nav-left">
|
||||||
<span class="layui-breadcrumb">
|
<span class="layui-breadcrumb">
|
||||||
<a class="kg-back" href="{{ back_url }}"><i class="layui-icon layui-icon-return"></i>返回</a>
|
<a href="{{ back_url }}"><i class="layui-icon layui-icon-return"></i>返回</a>
|
||||||
<a><cite>{{ course.title }}</cite></a>
|
<a><cite>{{ course.title }}</cite></a>
|
||||||
<a><cite>章节管理</cite></a>
|
<a><cite>章节管理</cite></a>
|
||||||
</span>
|
</span>
|
||||||
|
@ -25,9 +25,7 @@
|
|||||||
<div class="kg-nav-left">
|
<div class="kg-nav-left">
|
||||||
<span class="layui-breadcrumb">
|
<span class="layui-breadcrumb">
|
||||||
{% if parent.id > 0 %}
|
{% if parent.id > 0 %}
|
||||||
<a class="kg-back" href="{{ back_url }}">
|
<a href="{{ back_url }}"><i class="layui-icon layui-icon-return"></i>返回</a>
|
||||||
<i class="layui-icon layui-icon-return"></i> 返回
|
|
||||||
</a>
|
|
||||||
<a><cite>{{ parent.name }}</cite></a>
|
<a><cite>{{ parent.name }}</cite></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a><cite>导航管理</cite></a>
|
<a><cite>导航管理</cite></a>
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
{{ js_include('lib/layui/layui.js') }}
|
{{ js_include('lib/layui/layui.js') }}
|
||||||
{{ js_include('admin/js/common.js') }}
|
{{ js_include('admin/js/common.js') }}
|
||||||
|
{{ js_include('admin/js/fixbar.js') }}
|
||||||
|
|
||||||
{% block include_js %}{% endblock %}
|
{% block include_js %}{% endblock %}
|
||||||
{% block inline_js %}{% endblock %}
|
{% block inline_js %}{% endblock %}
|
||||||
|
@ -21,12 +21,11 @@
|
|||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<label class="layui-form-label" style="padding-top:30px;">头像</label>
|
<label class="layui-form-label" style="padding-top:30px;">头像</label>
|
||||||
<div class="layui-input-inline" style="width:80px;">
|
<div class="layui-input-inline" style="width:80px;">
|
||||||
<img id="avatar" class="kg-avatar" src="{{ user.avatar }}">
|
<img id="img-avatar" class="kg-avatar" src="{{ user.avatar }}">
|
||||||
<input type="hidden" name="avatar" value="{{ user.avatar }}">
|
<input type="hidden" name="avatar" value="{{ user.avatar }}">
|
||||||
<input type="hidden" name="default_avatar" value="{{ default_avatar }}">
|
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-input-inline" style="padding-top:25px;">
|
<div class="layui-input-inline" style="padding-top:25px;">
|
||||||
<button id="clear-avatar" class="layui-btn layui-btn-sm" type="button">清空</button>
|
<button id="change-avatar" class="layui-btn layui-btn-sm" type="button">更换</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
@ -153,6 +152,12 @@
|
|||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block include_js %}
|
||||||
|
|
||||||
|
{{ js_include('admin/js/avatar.upload.js') }}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block inline_js %}
|
{% block inline_js %}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -163,12 +168,6 @@
|
|||||||
var form = layui.form;
|
var form = layui.form;
|
||||||
var laydate = layui.laydate;
|
var laydate = layui.laydate;
|
||||||
|
|
||||||
$('#clear-avatar').on('click', function () {
|
|
||||||
var defaultAvatar = $('input[name=default_avatar]').val();
|
|
||||||
$('input[name=avatar]').val(defaultAvatar);
|
|
||||||
$('#avatar').attr('src', defaultAvatar);
|
|
||||||
});
|
|
||||||
|
|
||||||
laydate.render({
|
laydate.render({
|
||||||
elem: 'input[name=vip_expiry_time]',
|
elem: 'input[name=vip_expiry_time]',
|
||||||
type: 'datetime'
|
type: 'datetime'
|
||||||
|
@ -30,8 +30,6 @@ class Controller extends \Phalcon\Mvc\Controller
|
|||||||
$this->setCors();
|
$this->setCors();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->checkRateLimit();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,20 +120,17 @@ class ConnectController extends Controller
|
|||||||
$service = new ConnectService();
|
$service = new ConnectService();
|
||||||
|
|
||||||
$openUser = $service->getOpenUserInfo($code, $state, $provider);
|
$openUser = $service->getOpenUserInfo($code, $state, $provider);
|
||||||
|
|
||||||
$connect = $service->getConnectRelation($openUser['id'], $openUser['provider']);
|
$connect = $service->getConnectRelation($openUser['id'], $openUser['provider']);
|
||||||
|
|
||||||
if ($this->authUser->id > 0) {
|
if ($this->authUser->id > 0 && $openUser) {
|
||||||
if ($openUser) {
|
|
||||||
$service->bindUser($openUser);
|
$service->bindUser($openUser);
|
||||||
return $this->response->redirect(['for' => 'home.uc.account']);
|
return $this->response->redirect(['for' => 'home.uc.account']);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if ($connect) {
|
if ($this->authUser->id == 0 && $connect) {
|
||||||
$service->authConnectLogin($connect);
|
$service->authConnectLogin($connect);
|
||||||
return $this->response->redirect(['for' => 'home.index']);
|
return $this->response->redirect(['for' => 'home.index']);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$this->seo->prependTitle('绑定帐号');
|
$this->seo->prependTitle('绑定帐号');
|
||||||
|
|
||||||
|
@ -77,8 +77,6 @@ class Controller extends \Phalcon\Mvc\Controller
|
|||||||
$this->checkCsrfToken();
|
$this->checkCsrfToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->checkRateLimit();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,6 @@ class LayerController extends \Phalcon\Mvc\Controller
|
|||||||
$this->checkCsrfToken();
|
$this->checkCsrfToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->checkRateLimit();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,6 @@
|
|||||||
</form>
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="register-close-tips">
|
<div class="register-close-tips">
|
||||||
<i class="layui-icon layui-icon-tips"></i> 邮箱注册已关闭
|
<i class="layui-icon layui-icon-lock"></i> 邮箱注册已关闭
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
@ -36,6 +36,6 @@
|
|||||||
</form>
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="register-close-tips">
|
<div class="register-close-tips">
|
||||||
<i class="layui-icon layui-icon-tips"></i> 手机注册已关闭
|
<i class="layui-icon layui-icon-lock"></i> 手机注册已关闭
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
@ -98,9 +98,11 @@
|
|||||||
{% if lesson.attrs.stream.status == 'active' %}
|
{% if lesson.attrs.stream.status == 'active' %}
|
||||||
<span class="flag flag-active">直播中</span>
|
<span class="flag flag-active">直播中</span>
|
||||||
{% elseif lesson.attrs.start_time > time() %}
|
{% elseif lesson.attrs.start_time > time() %}
|
||||||
<span class="flag flag-pending">倒计时</span>
|
<span class="flag flag-scheduled">倒计时</span>
|
||||||
{% elseif lesson.attrs.end_time < time() %}
|
{% elseif lesson.attrs.end_time < time() %}
|
||||||
<span class="flag flag-ended">已结束</span>
|
<span class="flag flag-ended">已结束</span>
|
||||||
|
{% elseif lesson.attrs.stream.status == 'inactive' %}
|
||||||
|
<span class="flag flag-inactive">未推流</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
@ -108,7 +110,7 @@
|
|||||||
{% if lesson.attrs.start_time < time() and lesson.attrs.end_time > time() %}
|
{% if lesson.attrs.start_time < time() and lesson.attrs.end_time > time() %}
|
||||||
<span class="flag flag-active">授课中</span>
|
<span class="flag flag-active">授课中</span>
|
||||||
{% elseif lesson.attrs.start_time > time() %}
|
{% elseif lesson.attrs.start_time > time() %}
|
||||||
<span class="flag flag-pending">未开始</span>
|
<span class="flag flag-scheduled">未开始</span>
|
||||||
{% elseif lesson.attrs.end_time < time() %}
|
{% elseif lesson.attrs.end_time < time() %}
|
||||||
<span class="flag flag-ended">已结束</span>
|
<span class="flag flag-ended">已结束</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -31,17 +31,10 @@
|
|||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block inline_js %}
|
{% block include_js %}
|
||||||
|
|
||||||
<script>
|
{{ js_include('lib/clipboard.min.js') }}
|
||||||
layui.use(['jquery', 'helper'], function () {
|
{{ js_include('home/js/help.show.js') }}
|
||||||
var $ = layui.jquery;
|
{{ js_include('home/js/copy.js') }}
|
||||||
var helper = layui.helper;
|
|
||||||
var $courseList = $('#course-list');
|
|
||||||
if ($courseList.length > 0) {
|
|
||||||
helper.ajaxLoadHtml($courseList.data('url'), $courseList.attr('id'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -30,17 +30,10 @@
|
|||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block inline_js %}
|
{% block include_js %}
|
||||||
|
|
||||||
<script>
|
{{ js_include('lib/clipboard.min.js') }}
|
||||||
layui.use(['jquery', 'helper'], function () {
|
{{ js_include('home/js/page.show.js') }}
|
||||||
var $ = layui.jquery;
|
{{ js_include('home/js/copy.js') }}
|
||||||
var helper = layui.helper;
|
|
||||||
var $courseList = $('#course-list');
|
|
||||||
if ($courseList.length > 0) {
|
|
||||||
helper.ajaxLoadHtml($courseList.data('url'), $courseList.attr('id'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -19,7 +19,7 @@
|
|||||||
{% if item.cover %}
|
{% if item.cover %}
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<a href="{{ article_url }}" target="_blank">
|
<a href="{{ article_url }}" target="_blank">
|
||||||
<img src="{{ item.cover }}!cover_270" alt="{{ item.title }}">
|
<img src="{{ item.cover }}!cover_270" alt="{{ item.title|striptags }}">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<div class="search-course-card">
|
<div class="search-course-card">
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<a href="{{ course_url }}" target="_blank">
|
<a href="{{ course_url }}" target="_blank">
|
||||||
<img src="{{ item.cover }}!cover_270" alt="{{ item.title }}">
|
<img src="{{ item.cover }}!cover_270" alt="{{ item.title|striptags }}">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
{% if item.cover %}
|
{% if item.cover %}
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<a href="{{ question_url }}" target="_blank">
|
<a href="{{ question_url }}" target="_blank">
|
||||||
<img src="{{ item.cover }}!cover_270" alt="{{ item.title }}">
|
<img src="{{ item.cover }}!cover_270" alt="{{ item.title|striptags }}">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-CN-Hans">
|
<html lang="zh-CN-Hans">
|
||||||
<head>
|
<head>
|
||||||
|
{% if site_info.analytics_enabled == 1 %}
|
||||||
|
{{ site_info.analytics_script }}
|
||||||
|
{% endif %}
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
@ -38,12 +41,5 @@
|
|||||||
|
|
||||||
{% block include_js %}{% endblock %}
|
{% block include_js %}{% endblock %}
|
||||||
{% block inline_js %}{% endblock %}
|
{% block inline_js %}{% endblock %}
|
||||||
|
|
||||||
{% if site_info.analytics_enabled == 1 %}
|
|
||||||
<div class="layui-hide">
|
|
||||||
{{ site_info.analytics_script }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -79,7 +79,6 @@
|
|||||||
|
|
||||||
{% block include_js %}
|
{% block include_js %}
|
||||||
|
|
||||||
{{ js_include('home/js/user.avatar.upload.js') }}
|
|
||||||
{{ js_include('home/js/user.console.profile.js') }}
|
{{ js_include('home/js/user.console.profile.js') }}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -16,7 +16,7 @@ class AppInfo
|
|||||||
|
|
||||||
protected $link = 'https://www.koogua.com';
|
protected $link = 'https://www.koogua.com';
|
||||||
|
|
||||||
protected $version = '1.7.7';
|
protected $version = '1.7.8';
|
||||||
|
|
||||||
public function __get($name)
|
public function __get($name)
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
use App\Caches\CourseChapterList as CatalogCache;
|
use App\Caches\CourseChapterList as CourseChapterListCache;
|
||||||
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;
|
||||||
@ -175,7 +175,7 @@ class LiveNotify extends Service
|
|||||||
|
|
||||||
protected function rebuildCatalogCache(ChapterModel $chapter)
|
protected function rebuildCatalogCache(ChapterModel $chapter)
|
||||||
{
|
{
|
||||||
$cache = new CatalogCache();
|
$cache = new CourseChapterListCache();
|
||||||
|
|
||||||
$cache->rebuild($chapter->course_id);
|
$cache->rebuild($chapter->course_id);
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,6 @@ class OrderConfirm extends LogicService
|
|||||||
'lesson_count' => $course->lesson_count,
|
'lesson_count' => $course->lesson_count,
|
||||||
'study_expiry' => $course->study_expiry,
|
'study_expiry' => $course->study_expiry,
|
||||||
'refund_expiry' => $course->refund_expiry,
|
'refund_expiry' => $course->refund_expiry,
|
||||||
'origin_price' => $course->origin_price,
|
|
||||||
'market_price' => $course->market_price,
|
'market_price' => $course->market_price,
|
||||||
'vip_price' => $course->vip_price,
|
'vip_price' => $course->vip_price,
|
||||||
];
|
];
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
|
||||||
* @license https://opensource.org/licenses/GPL-2.0
|
|
||||||
* @link https://www.koogua.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Services;
|
|
||||||
|
|
||||||
class Throttle extends Service
|
|
||||||
{
|
|
||||||
|
|
||||||
public function checkRateLimit()
|
|
||||||
{
|
|
||||||
$config = $this->getConfig();
|
|
||||||
|
|
||||||
if (!$config->path('throttle.enabled')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache = $this->getCache();
|
|
||||||
|
|
||||||
$sign = $this->getRequestSignature();
|
|
||||||
|
|
||||||
$cacheKey = $this->getCacheKey($sign);
|
|
||||||
|
|
||||||
if ($cache->ttl($cacheKey) < 1) {
|
|
||||||
$cache->save($cacheKey, 0, $config->path('throttle.lifetime'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$rateLimit = $cache->get($cacheKey);
|
|
||||||
|
|
||||||
if ($rateLimit >= $config->path('throttle.rate_limit')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache->increment($cacheKey, 1);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getRequestSignature()
|
|
||||||
{
|
|
||||||
$authUser = $this->getAuthUser();
|
|
||||||
|
|
||||||
if (!empty($authUser['id'])) {
|
|
||||||
return md5($authUser['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$httpHost = $this->request->getHttpHost();
|
|
||||||
$clientAddress = $this->request->getClientAddress();
|
|
||||||
|
|
||||||
if ($httpHost && $clientAddress) {
|
|
||||||
return md5($httpHost . '|' . $clientAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new \RuntimeException('Unable to generate request signature');
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getCacheKey($sign)
|
|
||||||
{
|
|
||||||
return "throttle:{$sign}";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -28,13 +28,6 @@ trait Security
|
|||||||
$validator->checkHttpReferer();
|
$validator->checkHttpReferer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkRateLimit()
|
|
||||||
{
|
|
||||||
$validator = new SecurityValidator();
|
|
||||||
|
|
||||||
$validator->checkRateLimit();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isNotSafeRequest()
|
public function isNotSafeRequest()
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -11,10 +11,7 @@ use App\Exceptions\BadRequest as BadRequestException;
|
|||||||
use App\Models\Order as OrderModel;
|
use App\Models\Order as OrderModel;
|
||||||
use App\Models\Refund as RefundModel;
|
use App\Models\Refund as RefundModel;
|
||||||
use App\Models\Trade as TradeModel;
|
use App\Models\Trade as TradeModel;
|
||||||
use App\Repos\Course as CourseRepo;
|
|
||||||
use App\Repos\Order as OrderRepo;
|
use App\Repos\Order as OrderRepo;
|
||||||
use App\Repos\Package as PackageRepo;
|
|
||||||
use App\Repos\Vip as VipRepo;
|
|
||||||
|
|
||||||
class Order extends Validator
|
class Order extends Validator
|
||||||
{
|
{
|
||||||
@ -50,54 +47,36 @@ class Order extends Validator
|
|||||||
return $order;
|
return $order;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkItemType($itemType)
|
public function checkItemType($type)
|
||||||
{
|
{
|
||||||
$list = OrderModel::itemTypes();
|
$types = OrderModel::itemTypes();
|
||||||
|
|
||||||
if (!array_key_exists($itemType, $list)) {
|
if (!array_key_exists($type, $types)) {
|
||||||
throw new BadRequestException('order.invalid_item_type');
|
throw new BadRequestException('order.invalid_item_type');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $itemType;
|
return $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkCourse($itemId)
|
public function checkCourse($id)
|
||||||
{
|
{
|
||||||
$courseRepo = new CourseRepo();
|
$validator = new Course();
|
||||||
|
|
||||||
$course = $courseRepo->findById($itemId);
|
return $validator->checkCourse($id);
|
||||||
|
|
||||||
if (!$course || $course->published == 0) {
|
|
||||||
throw new BadRequestException('order.item_not_found');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $course;
|
public function checkPackage($id)
|
||||||
}
|
|
||||||
|
|
||||||
public function checkPackage($itemId)
|
|
||||||
{
|
{
|
||||||
$packageRepo = new PackageRepo();
|
$validator = new Package();
|
||||||
|
|
||||||
$package = $packageRepo->findById($itemId);
|
return $validator->checkPackage($id);
|
||||||
|
|
||||||
if (!$package || $package->published == 0) {
|
|
||||||
throw new BadRequestException('order.item_not_found');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $package;
|
public function checkVip($id)
|
||||||
}
|
|
||||||
|
|
||||||
public function checkVip($itemId)
|
|
||||||
{
|
{
|
||||||
$vipRepo = new VipRepo();
|
$validator = new Vip();
|
||||||
|
|
||||||
$vip = $vipRepo->findById($itemId);
|
return $validator->checkVip($id);
|
||||||
|
|
||||||
if (!$vip || $vip->deleted == 1) {
|
|
||||||
throw new BadRequestException('order.item_not_found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $vip;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkAmount($amount)
|
public function checkAmount($amount)
|
||||||
@ -105,7 +84,7 @@ class Order extends Validator
|
|||||||
$value = $this->filter->sanitize($amount, ['trim', 'float']);
|
$value = $this->filter->sanitize($amount, ['trim', 'float']);
|
||||||
|
|
||||||
if ($value < 0.01 || $value > 100000) {
|
if ($value < 0.01 || $value > 100000) {
|
||||||
throw new BadRequestException('order.invalid_pay_amount');
|
throw new BadRequestException('order.invalid_amount');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
@ -148,7 +127,7 @@ class Order extends Validator
|
|||||||
];
|
];
|
||||||
|
|
||||||
if (!in_array($order->item_type, $types)) {
|
if (!in_array($order->item_type, $types)) {
|
||||||
throw new BadRequestException('order.refund_item_unsupported');
|
throw new BadRequestException('order.refund_not_supported');
|
||||||
}
|
}
|
||||||
|
|
||||||
$orderRepo = new OrderRepo();
|
$orderRepo = new OrderRepo();
|
||||||
@ -167,7 +146,7 @@ class Order extends Validator
|
|||||||
];
|
];
|
||||||
|
|
||||||
if ($refund && in_array($refund->status, $scopes)) {
|
if ($refund && in_array($refund->status, $scopes)) {
|
||||||
throw new BadRequestException('order.refund_apply_existed');
|
throw new BadRequestException('order.refund_request_existed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,9 +8,7 @@
|
|||||||
namespace App\Validators;
|
namespace App\Validators;
|
||||||
|
|
||||||
use App\Exceptions\BadRequest as BadRequestException;
|
use App\Exceptions\BadRequest as BadRequestException;
|
||||||
use App\Exceptions\ServiceUnavailable as ServiceUnavailableException;
|
|
||||||
use App\Library\CsrfToken as CsrfTokenService;
|
use App\Library\CsrfToken as CsrfTokenService;
|
||||||
use App\Services\Throttle as ThrottleService;
|
|
||||||
|
|
||||||
class Security extends Validator
|
class Security extends Validator
|
||||||
{
|
{
|
||||||
@ -53,17 +51,6 @@ class Security extends Validator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkRateLimit()
|
|
||||||
{
|
|
||||||
$service = new ThrottleService();
|
|
||||||
|
|
||||||
$result = $service->checkRateLimit();
|
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
throw new ServiceUnavailableException('security.too_many_requests');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getCsrfWhitelist()
|
protected function getCsrfWhitelist()
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
|
@ -91,7 +91,7 @@ class Trade extends Validator
|
|||||||
];
|
];
|
||||||
|
|
||||||
if ($refund && in_array($refund->status, $scopes)) {
|
if ($refund && in_array($refund->status, $scopes)) {
|
||||||
throw new BadRequestException('trade.refund_apply_existed');
|
throw new BadRequestException('trade.refund_request_existed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,21 +147,6 @@ $config['cors']['allow_headers'] = '*';
|
|||||||
*/
|
*/
|
||||||
$config['cors']['allow_methods'] = ['GET', 'POST', 'OPTIONS'];
|
$config['cors']['allow_methods'] = ['GET', 'POST', 'OPTIONS'];
|
||||||
|
|
||||||
/**
|
|
||||||
* 限流开启
|
|
||||||
*/
|
|
||||||
$config['throttle']['enabled'] = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 有效期(秒)
|
|
||||||
*/
|
|
||||||
$config['throttle']['lifetime'] = 60;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 限流频率
|
|
||||||
*/
|
|
||||||
$config['throttle']['rate_limit'] = 60;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 客户端ping服务端间隔(秒)
|
* 客户端ping服务端间隔(秒)
|
||||||
*/
|
*/
|
||||||
|
@ -22,7 +22,6 @@ $error['sys.unknown_error'] = '未知错误';
|
|||||||
/**
|
/**
|
||||||
* 安全相关
|
* 安全相关
|
||||||
*/
|
*/
|
||||||
$error['security.too_many_requests'] = '请求过于频繁';
|
|
||||||
$error['security.invalid_csrf_token'] = '无效的CSRF令牌';
|
$error['security.invalid_csrf_token'] = '无效的CSRF令牌';
|
||||||
$error['security.invalid_http_referer'] = '无效请求来源';
|
$error['security.invalid_http_referer'] = '无效请求来源';
|
||||||
|
|
||||||
@ -364,17 +363,15 @@ $error['slide.invalid_publish_status'] = '无效的发布状态';
|
|||||||
* 订单相关
|
* 订单相关
|
||||||
*/
|
*/
|
||||||
$error['order.not_found'] = '订单不存在';
|
$error['order.not_found'] = '订单不存在';
|
||||||
|
$error['order.invalid_amount'] = '无效的支付金额';
|
||||||
$error['order.invalid_status'] = '无效的状态类型';
|
$error['order.invalid_status'] = '无效的状态类型';
|
||||||
$error['order.item_not_found'] = '商品不存在';
|
|
||||||
$error['order.trade_expired'] = '交易已过期';
|
|
||||||
$error['order.is_delivering'] = '已经下过单了,正在准备发货中';
|
$error['order.is_delivering'] = '已经下过单了,正在准备发货中';
|
||||||
$error['order.has_bought_course'] = '已经购买过该课程';
|
$error['order.has_bought_course'] = '已经购买过该课程';
|
||||||
$error['order.has_bought_package'] = '已经购买过该套餐';
|
$error['order.has_bought_package'] = '已经购买过该套餐';
|
||||||
$error['order.cancel_not_allowed'] = '当前不允许取消订单';
|
$error['order.cancel_not_allowed'] = '当前不允许取消订单';
|
||||||
$error['order.close_not_allowed'] = '当前不允许关闭订单';
|
|
||||||
$error['order.refund_not_allowed'] = '当前不允许申请退款';
|
$error['order.refund_not_allowed'] = '当前不允许申请退款';
|
||||||
$error['order.refund_item_unsupported'] = '该品类不支持退款';
|
$error['order.refund_not_supported'] = '该品类不支持退款';
|
||||||
$error['order.refund_apply_existed'] = '退款申请已经存在';
|
$error['order.refund_request_existed'] = '退款申请已经存在';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 交易相关
|
* 交易相关
|
||||||
@ -385,7 +382,7 @@ $error['trade.invalid_channel'] = '无效的平台类型';
|
|||||||
$error['trade.invalid_status'] = '无效的状态类型';
|
$error['trade.invalid_status'] = '无效的状态类型';
|
||||||
$error['trade.close_not_allowed'] = '当前不允许关闭交易';
|
$error['trade.close_not_allowed'] = '当前不允许关闭交易';
|
||||||
$error['trade.refund_not_allowed'] = '当前不允许交易退款';
|
$error['trade.refund_not_allowed'] = '当前不允许交易退款';
|
||||||
$error['trade.refund_apply_existed'] = '退款申请已经存在,请等待处理结果';
|
$error['trade.refund_request_existed'] = '退款申请已经存在,请等待处理结果';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退款相关
|
* 退款相关
|
||||||
|
@ -294,21 +294,6 @@ final class V20210403184518 extends AbstractMigration
|
|||||||
protected function initSettingData()
|
protected function initSettingData()
|
||||||
{
|
{
|
||||||
$rows = [
|
$rows = [
|
||||||
[
|
|
||||||
'section' => 'captcha',
|
|
||||||
'item_key' => 'enabled',
|
|
||||||
'item_value' => '0',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'section' => 'captcha',
|
|
||||||
'item_key' => 'app_id',
|
|
||||||
'item_value' => '',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'section' => 'captcha',
|
|
||||||
'item_key' => 'secret_key',
|
|
||||||
'item_value' => '',
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
'section' => 'live.push',
|
'section' => 'live.push',
|
||||||
'item_key' => 'domain',
|
'item_key' => 'domain',
|
||||||
@ -392,7 +377,7 @@ final class V20210403184518 extends AbstractMigration
|
|||||||
[
|
[
|
||||||
'section' => 'mail',
|
'section' => 'mail',
|
||||||
'item_key' => 'smtp_host',
|
'item_key' => 'smtp_host',
|
||||||
'item_value' => 'smtp.163.com',
|
'item_value' => '',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'section' => 'mail',
|
'section' => 'mail',
|
||||||
@ -412,22 +397,22 @@ final class V20210403184518 extends AbstractMigration
|
|||||||
[
|
[
|
||||||
'section' => 'mail',
|
'section' => 'mail',
|
||||||
'item_key' => 'smtp_username',
|
'item_key' => 'smtp_username',
|
||||||
'item_value' => 'xxx@163.com',
|
'item_value' => '',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'section' => 'mail',
|
'section' => 'mail',
|
||||||
'item_key' => 'smtp_password',
|
'item_key' => 'smtp_password',
|
||||||
'item_value' => 'xxx',
|
'item_value' => '',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'section' => 'mail',
|
'section' => 'mail',
|
||||||
'item_key' => 'smtp_from_email',
|
'item_key' => 'smtp_from_email',
|
||||||
'item_value' => 'xxx@163.com',
|
'item_value' => '',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'section' => 'mail',
|
'section' => 'mail',
|
||||||
'item_key' => 'smtp_from_name',
|
'item_key' => 'smtp_from_name',
|
||||||
'item_value' => 'XXX有限公司',
|
'item_value' => '',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'section' => 'pay.alipay',
|
'section' => 'pay.alipay',
|
||||||
@ -617,18 +602,18 @@ final class V20210403184518 extends AbstractMigration
|
|||||||
[
|
[
|
||||||
'section' => 'sms',
|
'section' => 'sms',
|
||||||
'item_key' => 'signature',
|
'item_key' => 'signature',
|
||||||
'item_value' => '酷瓜云课堂',
|
'item_value' => '',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'section' => 'sms',
|
'section' => 'sms',
|
||||||
'item_key' => 'template',
|
'item_key' => 'template',
|
||||||
'item_value' => json_encode([
|
'item_value' => json_encode([
|
||||||
'verify' => ['enabled' => 1, 'id' => ''],
|
'verify' => ['enabled' => 1, 'id' => 0],
|
||||||
'order_finish' => ['enabled' => 1, 'id' => ''],
|
'order_finish' => ['enabled' => 0, 'id' => 0],
|
||||||
'refund_finish' => ['enabled' => 1, 'id' => ''],
|
'refund_finish' => ['enabled' => 0, 'id' => 0],
|
||||||
'live_begin' => ['enabled' => 1, 'id' => ''],
|
'live_begin' => ['enabled' => 0, 'id' => 0],
|
||||||
'consult_reply' => ['enabled' => 1, 'id' => ''],
|
'consult_reply' => ['enabled' => 0, 'id' => 0],
|
||||||
'goods_deliver' => ['enabled' => 1, 'id' => ''],
|
'goods_deliver' => ['enabled' => 0, 'id' => 0],
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@ -835,12 +820,12 @@ final class V20210403184518 extends AbstractMigration
|
|||||||
'section' => 'wechat.oa',
|
'section' => 'wechat.oa',
|
||||||
'item_key' => 'notice_template',
|
'item_key' => 'notice_template',
|
||||||
'item_value' => json_encode([
|
'item_value' => json_encode([
|
||||||
'account_login' => ['enabled' => 1, 'id' => ''],
|
'account_login' => ['enabled' => 0, 'id' => 0],
|
||||||
'order_finish' => ['enabled' => 1, 'id' => ''],
|
'order_finish' => ['enabled' => 0, 'id' => 0],
|
||||||
'refund_finish' => ['enabled' => 1, 'id' => ''],
|
'refund_finish' => ['enabled' => 0, 'id' => 0],
|
||||||
'goods_deliver' => ['enabled' => 1, 'id' => ''],
|
'goods_deliver' => ['enabled' => 0, 'id' => 0],
|
||||||
'consult_reply' => ['enabled' => 1, 'id' => ''],
|
'consult_reply' => ['enabled' => 0, 'id' => 0],
|
||||||
'live_begin' => ['enabled' => 1, 'id' => ''],
|
'live_begin' => ['enabled' => 0, 'id' => 0],
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -9,28 +9,9 @@ layui.use(['jquery', 'layer', 'upload'], function () {
|
|||||||
url: '/admin/upload/avatar/img',
|
url: '/admin/upload/avatar/img',
|
||||||
accept: 'images',
|
accept: 'images',
|
||||||
acceptMime: 'image/*',
|
acceptMime: 'image/*',
|
||||||
size: 512,
|
|
||||||
auto: false,
|
|
||||||
before: function () {
|
before: function () {
|
||||||
layer.load();
|
layer.load();
|
||||||
},
|
},
|
||||||
choose: function (obj) {
|
|
||||||
var flag = true;
|
|
||||||
obj.preview(function (index, file, result) {
|
|
||||||
var img = new Image();
|
|
||||||
img.src = result;
|
|
||||||
img.onload = function () {
|
|
||||||
if (img.width < 1000 && img.height < 1000) {
|
|
||||||
obj.upload(index, file);
|
|
||||||
} else {
|
|
||||||
flag = false;
|
|
||||||
layer.msg("图片尺寸必须小于 1000 * 1000");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return flag;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
done: function (res, index, upload) {
|
done: function (res, index, upload) {
|
||||||
$('#img-avatar').attr('src', res.data.url);
|
$('#img-avatar').attr('src', res.data.url);
|
||||||
$('input[name=avatar]').val(res.data.url);
|
$('input[name=avatar]').val(res.data.url);
|
||||||
|
7
public/static/admin/js/fixbar.js
Normal file
7
public/static/admin/js/fixbar.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
layui.use(['util'], function () {
|
||||||
|
|
||||||
|
var util = layui.util;
|
||||||
|
|
||||||
|
util.fixbar();
|
||||||
|
|
||||||
|
});
|
@ -1096,7 +1096,7 @@
|
|||||||
color: orange;
|
color: orange;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lesson-item .flag-pending {
|
.lesson-item .flag-scheduled {
|
||||||
border: 1px solid green;
|
border: 1px solid green;
|
||||||
color: green;
|
color: green;
|
||||||
}
|
}
|
||||||
@ -1106,6 +1106,11 @@
|
|||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lesson-item .flag-inactive {
|
||||||
|
border: 1px solid gray;
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
.lesson-item .flag-ended {
|
.lesson-item .flag-ended {
|
||||||
border: 1px solid gray;
|
border: 1px solid gray;
|
||||||
color: gray;
|
color: gray;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
layui.use(['jquery', 'helper', 'util'], function () {
|
layui.use(['jquery', 'util'], function () {
|
||||||
|
|
||||||
var $ = layui.jquery;
|
var $ = layui.jquery;
|
||||||
var util = layui.util;
|
var util = layui.util;
|
||||||
@ -47,6 +47,19 @@ layui.use(['jquery', 'helper', 'util'], function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var showPhoneCode = function () {
|
||||||
|
var content = '<div class="layui-font-32 layui-font-red layui-padding-5">';
|
||||||
|
content += '<i class="iconfont icon-phone layui-padding-1 layui-font-28"></i>' + window.contact.phone;
|
||||||
|
content += '</div>';
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: false,
|
||||||
|
closeBtn: 0,
|
||||||
|
shadeClose: true,
|
||||||
|
content: content,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var bars = [];
|
var bars = [];
|
||||||
|
|
||||||
if (window.contact.wechat) {
|
if (window.contact.wechat) {
|
||||||
@ -63,6 +76,13 @@ layui.use(['jquery', 'helper', 'util'], function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (window.contact.phone) {
|
||||||
|
bars.push({
|
||||||
|
type: 'phone',
|
||||||
|
content: '<i class="iconfont icon-phone layui-font-30"></i>',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
util.fixbar({
|
util.fixbar({
|
||||||
bars: bars,
|
bars: bars,
|
||||||
click: function (type) {
|
click: function (type) {
|
||||||
@ -70,24 +90,30 @@ layui.use(['jquery', 'helper', 'util'], function () {
|
|||||||
showWechatCode();
|
showWechatCode();
|
||||||
} else if (type === 'qq') {
|
} else if (type === 'qq') {
|
||||||
showQQCode();
|
showQQCode();
|
||||||
|
} else if (type === 'phone') {
|
||||||
|
showPhoneCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.icon-wechat').on('click', function () {
|
$('.contact > .wechat').on('click', function () {
|
||||||
showWechatCode();
|
showWechatCode();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.icon-qq').on('click', function () {
|
$('.contact > .qq').on('click', function () {
|
||||||
showQQCode();
|
showQQCode();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.icon-toutiao').on('click', function () {
|
$('.contact > .toutiao').on('click', function () {
|
||||||
showTouTiaoCode();
|
showTouTiaoCode();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.icon-douyin').on('click', function () {
|
$('.contact > .douyin').on('click', function () {
|
||||||
showDouYinCode();
|
showDouYinCode();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('.contact > .phone').on('click', function () {
|
||||||
|
showPhoneCode();
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
12
public/static/home/js/help.show.js
Normal file
12
public/static/home/js/help.show.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
layui.use(['jquery', 'helper'], function () {
|
||||||
|
|
||||||
|
var $ = layui.jquery;
|
||||||
|
var helper = layui.helper;
|
||||||
|
|
||||||
|
var $courseList = $('#course-list');
|
||||||
|
|
||||||
|
if ($courseList.length > 0) {
|
||||||
|
helper.ajaxLoadHtml($courseList.data('url'), $courseList.attr('id'));
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
12
public/static/home/js/page.show.js
Normal file
12
public/static/home/js/page.show.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
layui.use(['jquery', 'helper'], function () {
|
||||||
|
|
||||||
|
var $ = layui.jquery;
|
||||||
|
var helper = layui.helper;
|
||||||
|
|
||||||
|
var $courseList = $('#course-list');
|
||||||
|
|
||||||
|
if ($courseList.length > 0) {
|
||||||
|
helper.ajaxLoadHtml($courseList.data('url'), $courseList.attr('id'));
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
@ -1,44 +0,0 @@
|
|||||||
layui.use(['jquery', 'layer', 'upload'], function () {
|
|
||||||
|
|
||||||
var $ = layui.jquery;
|
|
||||||
var layer = layui.layer;
|
|
||||||
var upload = layui.upload;
|
|
||||||
|
|
||||||
upload.render({
|
|
||||||
elem: '#change-avatar',
|
|
||||||
url: '/upload/avatar/img',
|
|
||||||
accept: 'images',
|
|
||||||
acceptMime: 'image/*',
|
|
||||||
size: 512,
|
|
||||||
auto: false,
|
|
||||||
before: function () {
|
|
||||||
layer.load();
|
|
||||||
},
|
|
||||||
choose: function (obj) {
|
|
||||||
var flag = true;
|
|
||||||
obj.preview(function (index, file, result) {
|
|
||||||
var img = new Image();
|
|
||||||
img.src = result;
|
|
||||||
img.onload = function () {
|
|
||||||
if (img.width < 1000 && img.height < 1000) {
|
|
||||||
obj.upload(index, file);
|
|
||||||
} else {
|
|
||||||
flag = false;
|
|
||||||
layer.msg("图片尺寸必须小于 1000 * 1000");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return flag;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
done: function (res, index, upload) {
|
|
||||||
$('#img-avatar').attr('src', res.data.url);
|
|
||||||
$('input[name=avatar]').val(res.data.url);
|
|
||||||
layer.closeAll('loading');
|
|
||||||
},
|
|
||||||
error: function (index, upload) {
|
|
||||||
layer.msg('上传文件失败', {icon: 2});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
@ -1,7 +1,47 @@
|
|||||||
layui.use(['layarea'], function () {
|
layui.use(['jquery', 'upload', 'layer', 'layarea'], function () {
|
||||||
|
|
||||||
|
var $ = layui.jquery;
|
||||||
|
var layer = layui.layer;
|
||||||
|
var upload = layui.upload;
|
||||||
var layarea = layui.layarea;
|
var layarea = layui.layarea;
|
||||||
|
|
||||||
|
upload.render({
|
||||||
|
elem: '#change-avatar',
|
||||||
|
url: '/upload/avatar/img',
|
||||||
|
accept: 'images',
|
||||||
|
acceptMime: 'image/*',
|
||||||
|
size: 512,
|
||||||
|
auto: false,
|
||||||
|
before: function () {
|
||||||
|
layer.load();
|
||||||
|
},
|
||||||
|
choose: function (obj) {
|
||||||
|
var flag = true;
|
||||||
|
obj.preview(function (index, file, result) {
|
||||||
|
var img = new Image();
|
||||||
|
img.src = result;
|
||||||
|
img.onload = function () {
|
||||||
|
if (img.width < 1000 && img.height < 1000) {
|
||||||
|
obj.upload(index, file);
|
||||||
|
} else {
|
||||||
|
flag = false;
|
||||||
|
layer.msg("图片尺寸必须小于 1000 * 1000");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return flag;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
done: function (res) {
|
||||||
|
$('#img-avatar').attr('src', res.data.url);
|
||||||
|
$('input[name=avatar]').val(res.data.url);
|
||||||
|
layer.closeAll('loading');
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
layer.msg('上传文件失败', {icon: 2});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
layarea.render({
|
layarea.render({
|
||||||
elem: '#area-picker',
|
elem: '#area-picker',
|
||||||
change: function (res) {
|
change: function (res) {
|
||||||
|
@ -63,6 +63,9 @@ $scheduler->php($script, $bin, ['--task' => 'sync_article_score', '--action' =>
|
|||||||
$scheduler->php($script, $bin, ['--task' => 'sync_question_score', '--action' => 'main'])
|
$scheduler->php($script, $bin, ['--task' => 'sync_question_score', '--action' => 'main'])
|
||||||
->hourly(29);
|
->hourly(29);
|
||||||
|
|
||||||
|
$scheduler->php($script, $bin, ['--task' => 'close_live', '--action' => 'main'])
|
||||||
|
->hourly(31);
|
||||||
|
|
||||||
$scheduler->php($script, $bin, ['--task' => 'clean_log', '--action' => 'main'])
|
$scheduler->php($script, $bin, ['--task' => 'clean_log', '--action' => 'main'])
|
||||||
->daily(3, 3);
|
->daily(3, 3);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user