1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-06-25 04:07:17 +08:00

Merge branch 'koogua/v1.5.4' into demo

# Conflicts:
#	app/Http/Admin/Views/public/login.volt
#	app/Http/Home/Views/account/login_by_password.volt
This commit is contained in:
koogua 2022-06-16 09:20:25 +08:00
commit ab06bbe74c
29 changed files with 161 additions and 118 deletions

View File

@ -1,6 +1,15 @@
### [v1.5.4](https://gitee.com/koogua/course-tencent-cloud/releases/v1.5.4)(2022-06-30)
### [v1.5.4](https://gitee.com/koogua/course-tencent-cloud/releases/v1.5.4)(2022-06-15)
- 增加migration助手SettingTrait
- 增加积分兑换会员
- 增加ISP备案和电子执照配置
- 增加获取视频时长补偿机制
- 优化课程和套餐发货
- 优化验证码
- 优化视频点播回调处理任务
- 优化章节排序初始值和步长
- 优化后台视频上传和转码
- 修正获取子分类查询条件
### [v1.5.3](https://gitee.com/koogua/course-tencent-cloud/releases/v1.5.3)(2022-05-30)

View File

@ -20,23 +20,23 @@ class CategoryList extends Cache
return $this->lifetime;
}
public function getKey($type = null)
public function getKey($id = null)
{
return "category_list:{$type}";
return "category_list:{$id}";
}
/**
* @param null $type
* @param null $id
* @return array
*/
public function getContent($type = null)
public function getContent($id = null)
{
/**
* @var Resultset $categories
*/
$categories = CategoryModel::query()
->columns(['id', 'parent_id', 'name', 'priority', 'level', 'path'])
->where('type = :type:', ['type' => $type])
->where('type = :type:', ['type' => $id])
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('level ASC, priority ASC')

View File

@ -19,16 +19,16 @@ class CategoryTreeList extends Cache
return $this->lifetime;
}
public function getKey($type = null)
public function getKey($id = null)
{
return "category_tree_list:{$type}";
return "category_tree_list:{$id}";
}
public function getContent($type = null)
public function getContent($id = null)
{
$builder = new CategoryTreeListBuilder();
$list = $builder->handle($type);
$list = $builder->handle($id);
return $list ?: [];
}

View File

@ -145,6 +145,33 @@ class DeliverTask extends Task
$service = new VipDeliverService();
$service->handle($vip, $user);
/**
* 先下单购买课程,发现会员有优惠,于是购买会员,再回头购买课程
* 自动关闭未支付订单,让用户可以使用会员价再次下单
*/
$this->closePendingOrders($user->id);
}
protected function closePendingOrders($userId)
{
$orders = $this->findUserPendingOrders($userId);
if ($orders->count() == 0) return;
$itemTypes = [
OrderModel::ITEM_COURSE,
OrderModel::ITEM_PACKAGE,
];
foreach ($orders as $order) {
$case1 = in_array($order->item_type, $itemTypes);
$case2 = $order->promotion_type == 0;
if ($case1 && $case2) {
$order->status = OrderModel::STATUS_CLOSED;
$order->update();
}
}
}
protected function handleOrderConsumePoint(OrderModel $order)
@ -209,6 +236,20 @@ class DeliverTask extends Task
]);
}
/**
* @param int $userId
* @return ResultsetInterface|Resultset|OrderModel[]
*/
protected function findUserPendingOrders($userId)
{
$status = OrderModel::STATUS_PENDING;
return OrderModel::query()
->where('owner_id = :owner_id:', ['owner_id' => $userId])
->andWhere('status = :status:', ['status' => $status])
->execute();
}
/**
* @param int $limit
* @return ResultsetInterface|Resultset|TaskModel[]

View File

@ -50,6 +50,7 @@ class Article extends Service
'type' => CategoryModel::TYPE_ARTICLE,
'level' => 1,
'published' => 1,
'deleted' => 0,
]);
}

View File

@ -74,7 +74,10 @@ class FlashSale extends Service
{
$packageRepo = new PackageRepo();
$items = $packageRepo->findAll(['published' => 1]);
$items = $packageRepo->findAll([
'published' => 1,
'deleted' => 0,
]);
if ($items->count() == 0) return [];

View File

@ -49,6 +49,7 @@ class Question extends Service
'type' => CategoryModel::TYPE_ARTICLE,
'level' => 1,
'published' => 1,
'deleted' => 0,
]);
}

View File

@ -43,7 +43,7 @@ class Session extends Service
$validator = new CaptchaValidator();
$validator->checkCode($post['ticket'], $post['rand']);
$validator->checkCode($post['captcha']['ticket'], $post['captcha']['rand']);
}
$this->auth->saveAuthInfo($user);

View File

@ -48,8 +48,15 @@
</fieldset>
<div class="layui-form-item" id="upload-block">
<label class="layui-form-label">视频文件</label>
<div class="layui-input-block">
<span class="layui-btn" id="upload-btn">选择视频</span>
<div class="layui-input-inline">
<input class="layui-input" type="text" name="file_id" value="{{ file_id }}" readonly="readonly" lay-verify="required">
</div>
<div class="layui-inline">
{% if vod.file_id > 0 %}
<span class="layui-btn" id="upload-btn">重新上传</span>
{% else %}
<span class="layui-btn" id="upload-btn">选择视频</span>
{% endif %}
<input class="layui-hide" type="file" name="file" accept="video/*,audio/*">
</div>
</div>
@ -61,12 +68,6 @@
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">文件编号</label>
<div class="layui-input-block">
<input class="layui-input" type="text" name="file_id" value="{{ file_id }}" readonly="readonly" lay-verify="required">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"></label>
<div class="layui-input-block">

View File

@ -7,12 +7,12 @@
<div class="kg-login-wrap">
<div class="layui-card">
<div class="layui-card-header">管理登录</div>
<div class="layui-card-header">后台登录</div>
<div class="layui-card-body">
<form class="layui-form kg-login-form" method="POST" action="{{ url({'for':'admin.login'}) }}">
<div class="layui-form-item">
<label class="layui-icon layui-icon-username"></label>
<input class="layui-input" type="text" name="account" value="100015@163.com" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
<input id="cl-account" class="layui-input" type="text" name="account" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
</div>
<div class="layui-form-item">
<label class="layui-icon layui-icon-password"></label>
@ -21,15 +21,17 @@
{% if captcha.enabled == 1 %}
<div id="captcha-block" class="layui-form-item">
<div class="layui-input-block">
<button id="captcha-btn" class="layui-btn layui-btn-fluid" type="button" data-app-id="{{ captcha.app_id }}">点击完成验证</button>
<button id="cl-emit-btn" class="layui-btn layui-btn-fluid" type="button">点击完成验证</button>
</div>
</div>
{% endif %}
<div class="layui-form-item">
<div class="layui-input-block">
<button id="submit-btn" class="layui-btn layui-btn-fluid {{ disabled_class }}" {{ disabled_submit }} lay-submit="true" lay-filter="go">立即登录</button>
<input type="hidden" name="ticket">
<input type="hidden" name="rand">
<button id="cl-submit-btn" class="layui-btn layui-btn-fluid {{ disabled_class }}" {{ disabled_submit }} lay-submit="true" lay-filter="go">立即登录</button>
<input id="cl-captcha-enabled" type="hidden" value="{{ captcha.enabled }}">
<input id="cl-captcha-appId" type="hidden" value="{{ captcha.app_id }}">
<input id="cl-captcha-ticket" type="hidden" name="captcha[ticket]">
<input id="cl-captcha-rand" type="hidden" name="captcha[rand]">
</div>
</div>
</form>
@ -72,12 +74,7 @@
{{ js_include('lib/jquery.min.js') }}
{{ js_include('lib/jquery.buoyant.min.js') }}
{% if captcha.enabled == 1 %}
{{ js_include('https://ssl.captcha.qq.com/TCaptcha.js', false) }}
{% endif %}
{{ js_include('https://ssl.captcha.qq.com/TCaptcha.js', false) }}
{% endblock %}
@ -98,24 +95,27 @@
});
</script>
{% if captcha.enabled == 1 %}
<script>
layui.use(['jquery', 'form'], function () {
var $ = layui.jquery;
new TencentCaptcha(
$('#captcha-btn')[0],
$('#captcha-btn').data('app-id'),
<script>
layui.use(['jquery'], function () {
var $ = layui.jquery;
if ($('#cl-captcha-enabled').val() === '1') {
var captcha = new TencentCaptcha(
$('#cl-emit-btn')[0],
$('#cl-captcha-appId').val(),
function (res) {
if (res.ret === 0) {
$('input[name=ticket]').val(res.ticket);
$('input[name=rand]').val(res.randstr);
$('#cl-captcha-ticket').val(res.ticket);
$('#cl-captcha-rand').val(res.randstr);
$('#cl-submit-btn').removeClass('layui-btn-disabled').removeAttr('disabled');
$('#captcha-block').hide();
$('#submit-btn').removeClass('layui-btn-disabled').removeAttr('disabled');
}
}
);
});
</script>
{% endif %}
}
});
</script>
{% endblock %}

View File

@ -62,7 +62,7 @@ class Account extends Service
$validator = new CaptchaValidator();
$validator->checkCode($post['ticket'], $post['rand']);
$validator->checkCode($post['captcha']['ticket'], $post['captcha']['rand']);
}
$this->auth->saveAuthInfo($user);

View File

@ -29,10 +29,10 @@
<div class="layui-form-item">
<div class="layui-input-block">
<button id="cv-submit-btn" class="layui-btn layui-btn-fluid layui-btn-disabled" disabled="disabled" lay-submit="true" lay-filter="go">重置密码</button>
<input id="cv-enabled" type="hidden" value="{{ captcha.enabled }}">
<input id="cv-app-id" type="hidden" value="{{ captcha.app_id }}">
<input id="cv-ticket" type="hidden" name="ticket">
<input id="cv-rand" type="hidden" name="rand">
<input id="cv-captcha-enabled" type="hidden" value="{{ captcha.enabled }}">
<input id="cv-captcha-appId" type="hidden" value="{{ captcha.app_id }}">
<input id="cv-captcha-ticket" type="hidden" name="captcha[ticket]">
<input id="cv-captcha-rand" type="hidden" name="captcha[rand]">
</div>
</div>
</form>

View File

@ -4,7 +4,7 @@
<form class="layui-form account-form" method="POST" action="{{ url({'for':'home.account.pwd_login'}) }}">
<div class="layui-form-item">
<label class="layui-icon layui-icon-username"></label>
<input class="layui-input" type="text" name="account" value="100015@163.com" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
<input id="cl-account" class="layui-input" type="text" name="account" value="100015@163.com" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
</div>
<div class="layui-form-item">
<label class="layui-icon layui-icon-password"></label>
@ -13,16 +13,18 @@
{% if captcha.enabled == 1 %}
<div id="captcha-block" class="layui-form-item">
<div class="layui-input-block">
<button id="captcha-btn" class="layui-btn layui-btn-fluid" type="button" data-app-id="{{ captcha.app_id }}">点击完成验证</button>
<button id="cl-emit-btn" class="layui-btn layui-btn-fluid" type="button">点击完成验证</button>
</div>
</div>
{% endif %}
<div class="layui-form-item">
<div class="layui-input-block">
<button id="submit-btn" class="layui-btn layui-btn-fluid {{ disabled_class }}" {{ disabled_submit }} lay-submit="true" lay-filter="go">立即登录</button>
<button id="cl-submit-btn" class="layui-btn layui-btn-fluid {{ disabled_class }}" {{ disabled_submit }} lay-submit="true" lay-filter="go">立即登录</button>
<input type="hidden" name="return_url" value="{{ return_url }}">
<input id="ticket" type="hidden" name="ticket">
<input id="rand" type="hidden" name="rand">
<input id="cl-captcha-enabled" type="hidden" value="{{ captcha.enabled }}">
<input id="cl-captcha-appId" type="hidden" value="{{ captcha.app_id }}">
<input id="cl-captcha-ticket" type="hidden" name="captcha[ticket]">
<input id="cl-captcha-rand" type="hidden" name="captcha[rand]">
</div>
</div>
</form>

View File

@ -16,10 +16,10 @@
<div class="layui-input-block">
<button id="cv-submit-btn" class="layui-btn layui-btn-fluid layui-btn-disabled" disabled="disabled" lay-submit="true" lay-filter="go">立即登录</button>
<input type="hidden" name="return_url" value="{{ return_url }}">
<input id="cv-enabled" type="hidden" value="{{ captcha.enabled }}">
<input id="cv-app-id" type="hidden" value="{{ captcha.app_id }}">
<input id="cv-ticket" type="hidden" name="ticket">
<input id="cv-rand" type="hidden" name="rand">
<input id="cv-captcha-enabled" type="hidden" value="{{ captcha.enabled }}">
<input id="cv-captcha-appId" type="hidden" value="{{ captcha.app_id }}">
<input id="cv-captcha-ticket" type="hidden" name="captcha[ticket]">
<input id="cv-captcha-rand" type="hidden" name="captcha[rand]">
</div>
</div>
</form>

View File

@ -45,10 +45,10 @@
<div class="layui-input-block">
<button id="cv-submit-btn" class="layui-btn layui-btn-fluid layui-btn-disabled" disabled="disabled" lay-submit="true" lay-filter="go">注册帐号</button>
<input type="hidden" name="return_url" value="{{ return_url }}">
<input id="cv-enabled" type="hidden" value="{{ captcha.enabled }}">
<input id="cv-app-id" type="hidden" value="{{ captcha.app_id }}">
<input id="cv-ticket" type="hidden" name="ticket">
<input id="cv-rand" type="hidden" name="rand">
<input id="cv-captcha-enabled" type="hidden" value="{{ captcha.enabled }}">
<input id="cv-captcha-appId" type="hidden" value="{{ captcha.app_id }}">
<input id="cv-captcha-ticket" type="hidden" name="captcha[ticket]">
<input id="cv-captcha-rand" type="hidden" name="captcha[rand]">
</div>
</div>
</form>

View File

@ -34,10 +34,10 @@
<div class="layui-form-item">
<div class="layui-input-block">
<button id="cv-submit-btn" class="layui-btn layui-btn-fluid layui-btn-disabled" disabled="disabled" lay-submit="true" lay-filter="go">提交修改</button>
<input id="cv-enabled" type="hidden" value="{{ captcha.enabled }}">
<input id="cv-app-id" type="hidden" value="{{ captcha.app_id }}">
<input id="cv-ticket" type="hidden" name="ticket">
<input id="cv-rand" type="hidden" name="rand">
<input id="cv-captcha-enabled" type="hidden" value="{{ captcha.enabled }}">
<input id="cv-captcha-appId" type="hidden" value="{{ captcha.app_id }}">
<input id="cv-captcha-ticket" type="hidden" name="captcha[ticket]">
<input id="cv-captcha-rand" type="hidden" name="captcha[rand]">
</div>
</div>
</form>

View File

@ -34,10 +34,10 @@
<div class="layui-form-item">
<div class="layui-input-block">
<button id="cv-submit-btn" class="layui-btn layui-btn-fluid layui-btn-disabled" disabled="disabled" lay-submit="true" lay-filter="go">提交修改</button>
<input id="cv-enabled" type="hidden" value="{{ captcha.enabled }}">
<input id="cv-app-id" type="hidden" value="{{ captcha.app_id }}">
<input id="cv-ticket" type="hidden" name="ticket">
<input id="cv-rand" type="hidden" name="rand">
<input id="cv-captcha-enabled" type="hidden" value="{{ captcha.enabled }}">
<input id="cv-captcha-appId" type="hidden" value="{{ captcha.app_id }}">
<input id="cv-captcha-ticket" type="hidden" name="captcha[ticket]">
<input id="cv-captcha-rand" type="hidden" name="captcha[rand]">
</div>
</div>
</form>

View File

@ -100,7 +100,7 @@ class Account extends Model
$user = new User();
$user->id = $this->id;
$user->name = "user:{$this->id}";
$user->name = "user_{$this->id}";
if ($user->create() === false) {
throw new \RuntimeException('Create User Failed');

View File

@ -19,7 +19,10 @@ class XmTagList extends LogicService
{
$tagRepo = new TagRepo();
$allTags = $tagRepo->findAll(['published' => 1]);
$allTags = $tagRepo->findAll([
'published' => 1,
'deleted' => 0,
]);
if ($allTags->count() == 0) return [];

View File

@ -19,7 +19,10 @@ class XmTagList extends LogicService
{
$tagRepo = new TagRepo();
$allTags = $tagRepo->findAll(['published' => 1]);
$allTags = $tagRepo->findAll([
'published' => 1,
'deleted' => 0,
]);
if ($allTags->count() == 0) return [];

View File

@ -19,7 +19,10 @@ class XmTagList extends LogicService
{
$tagRepo = new TagRepo();
$allTags = $tagRepo->findAll(['published' => 1]);
$allTags = $tagRepo->findAll([
'published' => 1,
'deleted' => 0,
]);
if ($allTags->count() == 0) return [];

View File

@ -23,6 +23,7 @@ class TagList extends LogicService
$params = $pagerQuery->getParams();
$params['published'] = 1;
$params['deleted'] = 0;
$sort = $pagerQuery->getSort();
$page = $pagerQuery->getPage();

View File

@ -29,7 +29,7 @@ class MailCode extends LogicService
$validator = new CaptchaValidator();
$validator->checkCode($post['ticket'], $post['rand']);
$validator->checkCode($post['captcha']['ticket'], $post['captcha']['rand']);
}
$service = new MailVerifyService();

View File

@ -29,7 +29,7 @@ class SmsCode extends LogicService
$validator = new CaptchaValidator();
$validator->checkCode($post['ticket'], $post['rand']);
$validator->checkCode($post['captcha']['ticket'], $post['captcha']['rand']);
}
$service = new SmsVerifyService();

View File

@ -1,27 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Services\Logic\Verify;
use App\Services\Logic\Service as LogicService;
use App\Validators\Verify as VerifyValidator;
class Ticket extends LogicService
{
public function handle()
{
$rand = $this->request->getPost('rand', ['trim', 'string']);
$validator = new VerifyValidator();
$rand = $validator->checkRand($rand);
return $this->crypt->encryptBase64($rand);
}
}

View File

@ -1,7 +1,7 @@
<?php
/**
* @copyright Copyright (c) 2022 深圳市酷瓜软件有限公司
* @license https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/

View File

@ -1,7 +1,7 @@
<?php
/**
* @copyright Copyright (c) 2022 深圳市酷瓜软件有限公司
* @license https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/

View File

@ -2,16 +2,16 @@ layui.use(['jquery'], function () {
var $ = layui.jquery;
if ($('#captcha-btn').length > 0) {
if ($('#cl-captcha-enabled').val() === '1') {
var captcha = new TencentCaptcha(
$('#captcha-btn')[0],
$('#captcha-btn').data('app-id'),
$('#cl-emit-btn')[0],
$('#cl-captcha-appId').val(),
function (res) {
if (res.ret === 0) {
$('#ticket').val(res.ticket);
$('#rand').val(res.randstr);
$('#cl-captcha-ticket').val(res.ticket);
$('#cl-captcha-rand').val(res.randstr);
$('#cl-submit-btn').removeClass('layui-btn-disabled').removeAttr('disabled');
$('#captcha-block').hide();
$('#submit-btn').removeClass('layui-btn-disabled').removeAttr('disabled');
}
}
);

View File

@ -9,14 +9,14 @@ layui.use(['jquery', 'layer', 'util'], function () {
var $emit = $('#cv-emit-btn');
var $submit = $('#cv-submit-btn');
if ($('#cv-enabled').val() === '1') {
if ($('#cv-captcha-enabled').val() === '1') {
var captcha = new TencentCaptcha(
$emit[0],
$('#cv-app-id').val(),
$('#cv-captcha-appId').val(),
function (res) {
if (res.ret === 0) {
$('#cv-ticket').val(res.ticket);
$('#cv-rand').val(res.randstr);
$('#cv-captcha-ticket').val(res.ticket);
$('#cv-captcha-rand').val(res.randstr);
sendVerifyCode();
}
}
@ -49,8 +49,10 @@ layui.use(['jquery', 'layer', 'util'], function () {
if (isEmail($account.val()) || isPhone($account.val())) {
var postUrl;
var postData = {
ticket: $('#cv-ticket').val(),
rand: $('#cv-rand').val(),
captcha: {
ticket: $('#cv-captcha-ticket').val(),
rand: $('#cv-captcha-rand').val(),
}
};
if (isPhone($account.val())) {
postData.phone = $account.val();