mirror of
https://gitee.com/koogua/course-tencent-cloud.git
synced 2025-06-26 04:21:27 +08:00
增加课程推荐
This commit is contained in:
parent
a633f74e55
commit
0642d430ff
118
app/Caches/IndexFeaturedCourseList.php
Normal file
118
app/Caches/IndexFeaturedCourseList.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Category as CategoryModel;
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Services\Category as CategoryService;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
/**
|
||||
* 推荐课程
|
||||
*/
|
||||
class IndexFeaturedCourseList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'index_featured_course_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$categoryLimit = 5;
|
||||
|
||||
$courseLimit = 8;
|
||||
|
||||
$categories = $this->findCategories($categoryLimit);
|
||||
|
||||
if ($categories->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($categories as $category) {
|
||||
|
||||
$item = [];
|
||||
|
||||
$item['category'] = [
|
||||
'id' => $category->id,
|
||||
'name' => $category->name,
|
||||
];
|
||||
|
||||
$item['courses'] = [];
|
||||
|
||||
$courses = $this->findCategoryCourses($category->id, $courseLimit);
|
||||
|
||||
if ($courses->count() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$categoryCourses = [];
|
||||
|
||||
foreach ($courses as $course) {
|
||||
$categoryCourses[] = [
|
||||
'id' => $course->id,
|
||||
'title' => $course->title,
|
||||
'cover' => $course->cover,
|
||||
'market_price' => $course->market_price,
|
||||
'vip_price' => $course->vip_price,
|
||||
'model' => $course->model,
|
||||
'level' => $course->level,
|
||||
'user_count' => $course->user_count,
|
||||
'lesson_count' => $course->lesson_count,
|
||||
];
|
||||
}
|
||||
|
||||
$item['courses'] = $categoryCourses;
|
||||
|
||||
$result[] = $item;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|CategoryModel[]
|
||||
*/
|
||||
protected function findCategories($limit = 5)
|
||||
{
|
||||
return CategoryModel::query()
|
||||
->where('type = :type:', ['type' => CategoryModel::TYPE_COURSE])
|
||||
->andWhere('level = 1 AND published = 1')
|
||||
->orderBy('priority ASC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $categoryId
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|CourseModel[]
|
||||
*/
|
||||
protected function findCategoryCourses($categoryId, $limit = 8)
|
||||
{
|
||||
$categoryService = new CategoryService();
|
||||
|
||||
$categoryIds = $categoryService->getChildCategoryIds($categoryId);
|
||||
|
||||
return CourseModel::query()
|
||||
->inWhere('category_id', $categoryIds)
|
||||
->andWhere('published = 1')
|
||||
->andWhere('featured = 1')
|
||||
->orderBy('id DESC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
70
app/Caches/IndexSimpleFeaturedCourseList.php
Normal file
70
app/Caches/IndexSimpleFeaturedCourseList.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Course as CourseModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
/**
|
||||
* 简版推荐课程
|
||||
*/
|
||||
class IndexSimpleFeaturedCourseList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'index_simple_featured_course_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$limit = 8;
|
||||
|
||||
$courses = $this->findCourses($limit);
|
||||
|
||||
if ($courses->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($courses as $course) {
|
||||
$result[] = [
|
||||
'id' => $course->id,
|
||||
'title' => $course->title,
|
||||
'cover' => $course->cover,
|
||||
'market_price' => $course->market_price,
|
||||
'vip_price' => $course->vip_price,
|
||||
'model' => $course->model,
|
||||
'level' => $course->level,
|
||||
'user_count' => $course->user_count,
|
||||
'lesson_count' => $course->lesson_count,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|CourseModel[]
|
||||
*/
|
||||
protected function findCourses($limit = 8)
|
||||
{
|
||||
return CourseModel::query()
|
||||
->where('published = 1')
|
||||
->andWhere('featured = 1')
|
||||
->orderBy('id DESC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
@ -172,6 +172,10 @@ class Course extends Service
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($post['featured'])) {
|
||||
$data['featured'] = $validator->checkFeatureStatus($post['featured']);
|
||||
}
|
||||
|
||||
if (isset($post['published'])) {
|
||||
$data['published'] = $validator->checkPublishStatus($post['published']);
|
||||
if ($post['published'] == 1) {
|
||||
|
@ -59,6 +59,7 @@
|
||||
<col>
|
||||
<col>
|
||||
<col>
|
||||
<col>
|
||||
<col width="10%">
|
||||
</colgroup>
|
||||
<thead>
|
||||
@ -67,6 +68,7 @@
|
||||
<th>课时数</th>
|
||||
<th>用户数</th>
|
||||
<th>价格</th>
|
||||
<th>推荐</th>
|
||||
<th>发布</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
@ -101,6 +103,7 @@
|
||||
<p>市场:{{ '¥%0.2f'|format(item.market_price) }}</p>
|
||||
<p>会员:{{ '¥%0.2f'|format(item.vip_price) }}</p>
|
||||
</td>
|
||||
<td><input type="checkbox" name="featured" value="1" lay-skin="switch" lay-text="是|否" lay-filter="featured" data-url="{{ update_url }}" {% if item.featured == 1 %}checked="checked"{% endif %}></td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
@ -129,4 +132,45 @@
|
||||
|
||||
{{ partial('partials/pager') }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block inline_js %}
|
||||
|
||||
<script>
|
||||
|
||||
layui.define(['jquery', 'form', 'layer'], function () {
|
||||
|
||||
var $ = layui.jquery;
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
|
||||
form.on('switch(featured)', function (data) {
|
||||
var checked = $(this).is(':checked');
|
||||
var featured = checked ? 1 : 0;
|
||||
var url = $(this).data('url');
|
||||
var tips = featured === 1 ? '确定要推荐?' : '确定要取消推荐?';
|
||||
layer.confirm(tips, function () {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: url,
|
||||
data: {featured: featured},
|
||||
success: function (res) {
|
||||
layer.msg(res.msg, {icon: 1});
|
||||
},
|
||||
error: function (xhr) {
|
||||
var json = JSON.parse(xhr.responseText);
|
||||
layer.msg(json.msg, {icon: 2});
|
||||
data.elem.checked = !checked;
|
||||
form.render();
|
||||
}
|
||||
});
|
||||
}, function () {
|
||||
data.elem.checked = !checked;
|
||||
form.render();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
@ -54,6 +54,13 @@
|
||||
<input type="radio" name="free" value="0" title="否">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">推荐</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="featured" value="1" title="是">
|
||||
<input type="radio" name="featured" value="0" title="否">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">发布</label>
|
||||
<div class="layui-input-block">
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Api\Controllers;
|
||||
|
||||
use App\Caches\IndexSimpleFeaturedCourseList;
|
||||
use App\Caches\IndexSimpleFreeCourseList;
|
||||
use App\Caches\IndexSimpleNewCourseList;
|
||||
use App\Caches\IndexSimpleVipCourseList;
|
||||
@ -25,6 +26,18 @@ class IndexController extends Controller
|
||||
return $this->jsonSuccess(['slides' => $slides]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/courses/featured", name="api.index.featured_courses")
|
||||
*/
|
||||
public function featuredCoursesAction()
|
||||
{
|
||||
$cache = new IndexSimpleFeaturedCourseList();
|
||||
|
||||
$courses = $cache->get();
|
||||
|
||||
return $this->jsonSuccess(['courses' => $courses]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/courses/new", name="api.index.new_courses")
|
||||
*/
|
||||
|
@ -47,6 +47,7 @@ class IndexController extends Controller
|
||||
$this->view->pick('index/full');
|
||||
$this->view->setVar('lives', $service->getLives());
|
||||
$this->view->setVar('slides', $service->getSlides());
|
||||
$this->view->setVar('featured_courses', $service->getFeaturedCourses());
|
||||
$this->view->setVar('new_courses', $service->getNewCourses());
|
||||
$this->view->setVar('free_courses', $service->getFreeCourses());
|
||||
$this->view->setVar('vip_courses', $service->getVipCourses());
|
||||
@ -59,6 +60,7 @@ class IndexController extends Controller
|
||||
$this->view->pick('index/simple');
|
||||
$this->view->setVar('lives', $service->getLives());
|
||||
$this->view->setVar('slides', $service->getSlides());
|
||||
$this->view->setVar('featured_courses', $service->getSimpleFeaturedCourses());
|
||||
$this->view->setVar('new_courses', $service->getSimpleNewCourses());
|
||||
$this->view->setVar('free_courses', $service->getSimpleFreeCourses());
|
||||
$this->view->setVar('vip_courses', $service->getSimpleVipCourses());
|
||||
|
@ -2,9 +2,11 @@
|
||||
|
||||
namespace App\Http\Home\Services;
|
||||
|
||||
use App\Caches\IndexFeaturedCourseList;
|
||||
use App\Caches\IndexFreeCourseList;
|
||||
use App\Caches\IndexLiveList;
|
||||
use App\Caches\IndexNewCourseList;
|
||||
use App\Caches\IndexSimpleFeaturedCourseList;
|
||||
use App\Caches\IndexSimpleFreeCourseList;
|
||||
use App\Caches\IndexSimpleNewCourseList;
|
||||
use App\Caches\IndexSimpleVipCourseList;
|
||||
@ -61,6 +63,15 @@ class Index extends Service
|
||||
return $cache->get();
|
||||
}
|
||||
|
||||
public function getFeaturedCourses()
|
||||
{
|
||||
$cache = new IndexFeaturedCourseList();
|
||||
|
||||
$courses = $cache->get();
|
||||
|
||||
return $this->handleCategoryCourses($courses);
|
||||
}
|
||||
|
||||
public function getNewCourses()
|
||||
{
|
||||
$cache = new IndexNewCourseList();
|
||||
@ -95,6 +106,13 @@ class Index extends Service
|
||||
return $cache->get();
|
||||
}
|
||||
|
||||
public function getSimpleFeaturedCourses()
|
||||
{
|
||||
$cache = new IndexSimpleFeaturedCourseList();
|
||||
|
||||
return $cache->get();
|
||||
}
|
||||
|
||||
public function getSimpleFreeCourses()
|
||||
{
|
||||
$cache = new IndexSimpleFreeCourseList();
|
||||
|
@ -45,6 +45,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="index-wrap wrap">
|
||||
<div class="header">推荐课程</div>
|
||||
<div class="content">
|
||||
{{ category_courses(featured_courses) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="index-wrap wrap">
|
||||
<div class="header">新上课程</div>
|
||||
<div class="content">
|
||||
|
@ -30,6 +30,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="index-wrap wrap">
|
||||
<div class="header">推荐课程</div>
|
||||
<div class="content">
|
||||
{{ show_courses(featured_courses) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="index-wrap wrap">
|
||||
<div class="header">新上课程</div>
|
||||
<div class="content">
|
||||
|
@ -165,6 +165,13 @@ class Course extends Model
|
||||
*/
|
||||
public $attrs;
|
||||
|
||||
/**
|
||||
* 推荐标识
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $featured;
|
||||
|
||||
/**
|
||||
* 发布标识
|
||||
*
|
||||
@ -377,6 +384,7 @@ class Course extends Model
|
||||
'rating' => '好评',
|
||||
'latest' => '最新',
|
||||
'popular' => '最热',
|
||||
'featured' => '推荐',
|
||||
'free' => '免费',
|
||||
];
|
||||
}
|
||||
|
@ -67,6 +67,10 @@ class Course extends Repository
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($where['featured'])) {
|
||||
$builder->andWhere('featured = :featured:', ['featured' => $where['featured']]);
|
||||
}
|
||||
|
||||
if (isset($where['published'])) {
|
||||
$builder->andWhere('published = :published:', ['published' => $where['published']]);
|
||||
}
|
||||
@ -77,6 +81,8 @@ class Course extends Repository
|
||||
|
||||
if ($sort == 'free') {
|
||||
$builder->andWhere('market_price = 0');
|
||||
} elseif ($sort == 'featured') {
|
||||
$builder->andWhere('featured = 1');
|
||||
} elseif ($sort == 'vip_discount') {
|
||||
$builder->andWhere('vip_price < market_price');
|
||||
$builder->andWhere('vip_price > 0');
|
||||
|
@ -212,6 +212,15 @@ class Course extends Validator
|
||||
return $expiry;
|
||||
}
|
||||
|
||||
public function checkFeatureStatus($status)
|
||||
{
|
||||
if (!in_array($status, [0, 1])) {
|
||||
throw new BadRequestException('course.invalid_feature_status');
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
public function checkPublishStatus($status)
|
||||
{
|
||||
if (!in_array($status, [0, 1])) {
|
||||
|
@ -114,6 +114,7 @@ $error['course.invalid_vip_price'] = '无效的会员价格(范围:0-10000
|
||||
$error['course.invalid_compare_price'] = '无效的比较定价(会员价格高于市场价格)';
|
||||
$error['course.invalid_study_expiry'] = '无效的学习期限';
|
||||
$error['course.invalid_refund_expiry'] = '无效的退款期限';
|
||||
$error['course.invalid_feature_status'] = '无效的推荐状态';
|
||||
$error['course.invalid_publish_status'] = '无效的发布状态';
|
||||
$error['course.pub_chapter_not_found'] = '尚未发现已发布的课时';
|
||||
$error['course.pub_chapter_not_enough'] = '已发布的课时太少(小于30%)';
|
||||
|
21
db/migrations/20201227081614_schema_202012271615.php
Normal file
21
db/migrations/20201227081614_schema_202012271615.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
use Phinx\Db\Adapter\MysqlAdapter;
|
||||
|
||||
class Schema202012271615 extends Phinx\Migration\AbstractMigration
|
||||
{
|
||||
|
||||
public function change()
|
||||
{
|
||||
$this->table('kg_course')
|
||||
->addColumn('featured', 'integer', [
|
||||
'null' => false,
|
||||
'default' => '0',
|
||||
'limit' => MysqlAdapter::INT_REGULAR,
|
||||
'comment' => '推荐标识',
|
||||
'after' => 'attrs',
|
||||
])
|
||||
->save();
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user