1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-06-26 12:23:06 +08:00

增加课程推荐

This commit is contained in:
xiaochong0302 2020-12-27 17:55:27 +08:00
parent a633f74e55
commit 0642d430ff
15 changed files with 335 additions and 0 deletions

View 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();
}
}

View 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();
}
}

View File

@ -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) {

View File

@ -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">
@ -130,3 +133,44 @@
{{ 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 %}

View File

@ -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">

View File

@ -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")
*/

View File

@ -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());

View File

@ -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();

View File

@ -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">

View File

@ -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">

View File

@ -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' => '免费',
];
}

View File

@ -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');

View File

@ -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])) {

View File

@ -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%';

View 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();
}
}