1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-06-30 22:24:55 +08:00

去除评论,去除异步更新

This commit is contained in:
xiaochong0302 2020-07-21 20:12:33 +08:00
parent ac51d23934
commit 7f16e9710c
59 changed files with 464 additions and 1552 deletions

View File

@ -1,37 +0,0 @@
<?php
namespace App\Caches;
use App\Repos\Chapter as ChapterRepo;
class ChapterCounter extends Counter
{
protected $lifetime = 1 * 86400;
public function getLifetime()
{
return $this->lifetime;
}
public function getKey($id = null)
{
return "chapter_counter:{$id}";
}
public function getContent($id = null)
{
$chapterRepo = new ChapterRepo();
$chapter = $chapterRepo->findById($id);
if (!$chapter) return null;
return [
'user_count' => $chapter->user_count,
'consult_count' => $chapter->consult_count,
'like_count' => $chapter->like_count,
];
}
}

View File

@ -1,35 +0,0 @@
<?php
namespace App\Caches;
use App\Repos\Consult as ConsultRepo;
class ConsultCounter extends Counter
{
protected $lifetime = 1 * 86400;
public function getLifetime()
{
return $this->lifetime;
}
public function getKey($id = null)
{
return "consult_counter:{$id}";
}
public function getContent($id = null)
{
$consultRepo = new ConsultRepo();
$consult = $consultRepo->findById($id);
if (!$consult) return null;
return [
'like_count' => $consult->like_count,
];
}
}

View File

@ -1,40 +0,0 @@
<?php
namespace App\Caches;
use App\Repos\Course as CourseRepo;
class CourseCounter extends Counter
{
protected $lifetime = 1 * 86400;
public function getLifetime()
{
return $this->lifetime;
}
public function getKey($id = null)
{
return "course_counter:{$id}";
}
public function getContent($id = null)
{
$courseRepo = new CourseRepo();
$course = $courseRepo->findById($id);
if (!$course) return null;
return [
'user_count' => $course->user_count,
'lesson_count' => $course->lesson_count,
'comment_count' => $course->comment_count,
'consult_count' => $course->consult_count,
'review_count' => $course->review_count,
'favorite_count' => $course->favorite_count,
];
}
}

View File

@ -1,35 +0,0 @@
<?php
namespace App\Caches;
use App\Repos\Review as ReviewRepo;
class ReviewCounter extends Counter
{
protected $lifetime = 1 * 86400;
public function getLifetime()
{
return $this->lifetime;
}
public function getKey($id = null)
{
return "review_counter:{$id}";
}
public function getContent($id = null)
{
$reviewRepo = new ReviewRepo();
$review = $reviewRepo->findById($id);
if (!$review) return null;
return [
'like_count' => $review->like_count,
];
}
}

View File

@ -1,98 +0,0 @@
<?php
namespace App\Console\Tasks;
use App\Caches\Chapter as ChapterCache;
use App\Caches\ChapterCounter as ChapterCounterCache;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Repos\Chapter as ChapterRepo;
use App\Services\Syncer\ChapterCounter as ChapterCounterSyncer;
class SyncChapterCounterTask extends Task
{
/**
* @var RedisCache
*/
protected $cache;
/**
* @var \Redis
*/
protected $redis;
public function mainAction()
{
$this->cache = $this->getDI()->get('cache');
$this->redis = $this->cache->getRedis();
$this->rebuild();
}
protected function rebuild()
{
$key = $this->getCacheKey();
$chapterIds = $this->redis->sRandMember($key, 500);
if (!$chapterIds) return;
$chapterRepo = new ChapterRepo();
$chapters = $chapterRepo->findByIds($chapterIds);
if ($chapters->count() == 0) {
return;
}
$counterCache = new ChapterCounterCache();
$chapterCache = new ChapterCache();
$allowRecount = $this->allowRecount();
foreach ($chapters as $chapter) {
if ($allowRecount) {
$chapter->user_count = $chapterRepo->countUsers($chapter->id);
$chapter->comment_count = $chapterRepo->countComments($chapter->id);
$chapter->like_count = $chapterRepo->countLikes($chapter->id);
$chapter->update();
$counterCache->rebuild($chapter->id);
$chapterCache->rebuild($chapter->id);
} else {
$counter = $counterCache->get($chapter->id);
if ($counter) {
$chapter->user_count = $counter['user_count'];
$chapter->comment_count = $counter['comment_count'];
$chapter->like_count = $counter['like_count'];
$chapter->update();
$chapterCache->rebuild($chapter->id);
}
}
}
$this->redis->sRem($key, ...$chapterIds);
}
protected function getCacheKey()
{
$syncer = new ChapterCounterSyncer();
return $syncer->getSyncKey();
}
protected function allowRecount()
{
return date('H') % 3 == 0;
}
}

View File

@ -1,87 +0,0 @@
<?php
namespace App\Console\Tasks;
use App\Caches\ConsultCounter as ConsultCounterCache;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Repos\Consult as ConsultRepo;
use App\Services\Syncer\ConsultCounter as ConsultCounterSyncer;
class SyncConsultCounterTask extends Task
{
/**
* @var RedisCache
*/
protected $cache;
/**
* @var \Redis
*/
protected $redis;
public function mainAction()
{
$this->cache = $this->getDI()->get('cache');
$this->redis = $this->cache->getRedis();
$this->rebuild();
}
protected function rebuild()
{
$key = $this->getCacheKey();
$consultIds = $this->redis->sRandMember($key, 500);
if (!$consultIds) return;
$consultRepo = new ConsultRepo();
$consults = $consultRepo->findByIds($consultIds);
if ($consults->count() == 0) {
return;
}
$counterCache = new ConsultCounterCache();
$allowRecount = $this->allowRecount();
foreach ($consults as $consult) {
if ($allowRecount) {
$consult->like_count = $consultRepo->countLikes($consult->id);
$consult->update();
$counterCache->rebuild($consult->id);
} else {
$counter = $counterCache->get($consult->id);
if ($counter) {
$consult->like_count = $counter['like_count'];
$consult->update();
}
}
}
$this->redis->sRem($key, ...$consultIds);
}
protected function getCacheKey()
{
$syncer = new ConsultCounterSyncer();
return $syncer->getSyncKey();
}
protected function allowRecount()
{
return date('H') % 4 == 0;
}
}

View File

@ -1,102 +0,0 @@
<?php
namespace App\Console\Tasks;
use App\Caches\Course as CourseCache;
use App\Caches\CourseCounter as CourseCounterCache;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Repos\Course as CourseRepo;
use App\Services\Syncer\CourseCounter as CourseCounterSyncer;
class SyncCourseCounterTask extends Task
{
/**
* @var RedisCache
*/
protected $cache;
/**
* @var \Redis
*/
protected $redis;
public function mainAction()
{
$this->cache = $this->getDI()->get('cache');
$this->redis = $this->cache->getRedis();
$this->rebuild();
}
protected function rebuild()
{
$key = $this->getCacheKey();
$courseIds = $this->redis->sRandMember($key, 100);
if (!$courseIds) return;
$courseRepo = new CourseRepo();
$courses = $courseRepo->findByIds($courseIds);
if ($courses->count() == 0) {
return;
}
$counterCache = new CourseCounterCache();
$courseCache = new CourseCache();
$allowRecount = $this->allowRecount();
foreach ($courses as $course) {
if ($allowRecount) {
$course->user_count = $courseRepo->countUsers($course->id);
$course->comment_count = $courseRepo->countComments($course->id);
$course->consult_count = $courseRepo->countConsults($course->id);
$course->review_count = $courseRepo->countReviews($course->id);
$course->favorite_count = $courseRepo->countFavorites($course->id);
$course->update();
$counterCache->rebuild($course->id);
$courseCache->rebuild($course->id);
} else {
$counter = $counterCache->get($course->id);
if ($counter) {
$course->user_count = $counter['user_count'];
$course->comment_count = $counter['comment_count'];
$course->consult_count = $counter['consult_count'];
$course->review_count = $counter['review_count'];
$course->favorite_count = $counter['favorite_count'];
$course->update();
$courseCache->rebuild($course->id);
}
}
}
$this->redis->sRem($key, ...$courseIds);
}
protected function getCacheKey()
{
$syncer = new CourseCounterSyncer();
return $syncer->getSyncKey();
}
protected function allowRecount()
{
return date('H') % 3 == 0;
}
}

View File

@ -1,87 +0,0 @@
<?php
namespace App\Console\Tasks;
use App\Caches\ReviewCounter as ReviewCounterCache;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Repos\Review as ReviewRepo;
use App\Services\Syncer\ReviewCounter as ReviewCounterSyncer;
class SyncReviewCounterTask extends Task
{
/**
* @var RedisCache
*/
protected $cache;
/**
* @var \Redis
*/
protected $redis;
public function mainAction()
{
$this->cache = $this->getDI()->get('cache');
$this->redis = $this->cache->getRedis();
$this->rebuild();
}
protected function rebuild()
{
$key = $this->getCacheKey();
$reviewIds = $this->redis->sRandMember($key, 500);
if (!$reviewIds) return;
$reviewRepo = new ReviewRepo();
$reviews = $reviewRepo->findByIds($reviewIds);
if ($reviews->count() == 0) {
return;
}
$counterCache = new ReviewCounterCache();
$allowRecount = $this->allowRecount();
foreach ($reviews as $review) {
if ($allowRecount) {
$review->like_count = $reviewRepo->countLikes($review->id);
$review->update();
$counterCache->rebuild($review->id);
} else {
$counter = $counterCache->get($review->id);
if ($counter) {
$review->like_count = $counter['like_count'];
$review->update();
}
}
}
$this->redis->sRem($key, ...$reviewIds);
}
protected function getCacheKey()
{
$syncer = new ReviewCounterSyncer();
return $syncer->getSyncKey();
}
protected function allowRecount()
{
return date('H') % 4 == 0;
}
}

View File

@ -25,7 +25,7 @@
<p>类型:{{ item.client_type }}</p>
<p>地址:<a href="javascript:" class="kg-ip2region" title="查看位置" data-ip="{{ item.client_ip }}">{{ item.client_ip }}</a></p>
</td>
<td>{{ item.duration|total_duration }}</td>
<td>{{ item.duration|duration }}</td>
<td>{{ date('Y-m-d H:i:s',item.active_time) }}</td>
</tr>
{% endfor %}

View File

@ -61,7 +61,7 @@
</td>
<td>
<p>进度:{{ item.progress }}%</p>
<p>时长:{{ item.duration|total_duration }}</p>
<p>时长:{{ item.duration|duration }}</p>
</td>
<td>{{ source_type_info(item.source_type) }}</td>
<td>

View File

@ -71,10 +71,6 @@ class CourseController extends Controller
$course = $service->handle($id);
$service = new CourseQueryService();
$course['category_paths'] = $service->handleCategoryPaths($course['category_id']);
$service = new RewardOptionList();
$rewards = $service->handle();

View File

@ -51,6 +51,30 @@ class MyController extends Controller
$this->view->setVar('account', $account);
}
/**
* @Get("/courses", name="web.my.courses")
*/
public function coursesAction()
{
$service = new MyConsultListService();
$pager = $service->handle();
$this->view->setVar('pager', $pager);
}
/**
* @Get("/favorites", name="web.my.favorites")
*/
public function favoritesAction()
{
$service = new MyConsultListService();
$pager = $service->handle();
$this->view->setVar('pager', $pager);
}
/**
* @Get("/consults", name="web.my.consults")
*/

View File

@ -74,7 +74,7 @@
{{ js_include('web/js/chapter.live.player.js') }}
{{ js_include('web/js/chapter.live.im.js') }}
{{ js_include('web/js/chapter.like.js') }}
{{ js_include('web/js/chapter.action.js') }}
{{ js_include('web/js/course.share.js') }}
{% endblock %}

View File

@ -6,6 +6,7 @@
{% set course_url = url({'for':'web.course.show','id':chapter.course.id}) %}
{% set learning_url = url({'for':'web.chapter.learning','id':chapter.id}) %}
{% set like_url = url({'for':'web.chapter.like','id':chapter.id}) %}
{% set consult_url = url({'for':'web.consult.add'},{'chapter_id':chapter.id}) %}
{% set qrcode_url = url({'for':'web.qrcode_img'},{'text':chapter_full_url}) %}
<div class="breadcrumb">
@ -17,6 +18,7 @@
<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>{{ chapter.user_count }}</em></a>
<a href="javascript:" title="我要提问" data-url="{{ consult_url }}"><i class="layui-icon layui-icon-help icon-help"></i></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>
@ -49,8 +51,8 @@
{% block include_js %}
{{ js_include('web/js/chapter.read.js') }}
{{ js_include('web/js/chapter.like.js') }}
{{ js_include('web/js/course.share.js') }}
{{ js_include('web/js/chapter.read.js') }}
{{ js_include('web/js/chapter.action.js') }}
{% endblock %}

View File

@ -20,7 +20,7 @@
<span class="share">
<a href="javascript:" title="学习人次"><i class="layui-icon layui-icon-user"></i><em>{{ chapter.user_count }}</em></a>
<a href="javascript:" title="我要点赞" data-url="{{ like_url }}"><i class="layui-icon layui-icon-praise icon-praise {{ liked_class }}"></i><em class="like-count">{{ chapter.like_count }}</em></a>
<a href="javascript:" title="我要提问" data-url="{{ consult_url }}"><i class="layui-icon layui-icon-help icon-help"></i><em>{{ chapter.consult_count }}</em></a>
<a href="javascript:" title="我要提问" data-url="{{ consult_url }}"><i class="layui-icon layui-icon-help icon-help"></i></a>
<a href="javascript:" title="分享到微信"><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>
@ -119,8 +119,7 @@
{{ js_include('lib/jquery.min.js') }}
{{ js_include('lib/jquery.danmu.min.js') }}
{{ js_include('web/js/course.share.js') }}
{{ js_include('web/js/chapter.like.js') }}
{{ js_include('web/js/chapter.vod.js') }}
{{ js_include('web/js/chapter.action.js') }}
{{ js_include('web/js/chapter.vod.player.js') }}
{% endblock %}

View File

@ -8,9 +8,9 @@
<span class="layui-badge free-badge">免费</span>
{% endif %}
{% if lesson.me.duration > 0 %}
<span class="study-time" title="学习时长:{{ lesson.me.duration|total_duration }}"><i class="layui-icon layui-icon-time"></i></span>
<span class="study-time" title="学习时长:{{ lesson.me.duration|duration }}"><i class="layui-icon layui-icon-time"></i></span>
{% endif %}
<span class="duration">{{ lesson.attrs.duration|total_duration }}</span>
<span class="duration">{{ lesson.attrs.duration|duration }}</span>
</a>
{%- endmacro %}
@ -25,7 +25,7 @@
<span class="layui-badge free-badge">免费</span>
{% endif %}
{% if lesson.me.duration > 0 %}
<span class="study-time" title="学习时长:{{ lesson.me.duration|total_duration }}"><i class="layui-icon layui-icon-time"></i></span>
<span class="study-time" title="学习时长:{{ lesson.me.duration|duration }}"><i class="layui-icon layui-icon-time"></i></span>
{% endif %}
<span class="live">{{ date('m月d日',lesson.attrs.start_time) }} {{ date('H:i',lesson.attrs.start_time) }}~{{ date('H:i',lesson.attrs.end_time) }} {{ over_flag }}</span>
</a>
@ -41,7 +41,7 @@
<span class="layui-badge free-badge">免费</span>
{% endif %}
{% if lesson.me.duration > 0 %}
<span class="study-time" title="学习时长:{{ lesson.me.duration|total_duration }}"><i class="layui-icon layui-icon-time"></i></span>
<span class="study-time" title="学习时长:{{ lesson.me.duration|duration }}"><i class="layui-icon layui-icon-time"></i></span>
{% endif %}
</a>
{%- endmacro %}

View File

@ -85,10 +85,7 @@
<div class="layout-sidebar">
{{ partial('course/show_order') }}
{% if show_sidebar_teachers %}
{% set teachers_url = url({'for':'web.course.teachers','id':course.id}) %}
<div class="sidebar" id="sidebar-teachers" data-url="{{ teachers_url }}"></div>
{% endif %}
{{ partial('course/show_teacher') }}
{% if show_sidebar_topics %}
{% set topics_url = url({'for':'web.course.topics','id':course.id}) %}
<div class="sidebar" id="sidebar-topics" data-url="{{ topics_url }}"></div>

View File

@ -5,7 +5,7 @@
<div class="info">
{% if course.model == 'vod' %}
<p class="item">
<span class="key">课程时长</span><span class="value">{{ course.attrs.duration|total_duration }}</span>
<span class="key">课程时长</span><span class="value">{{ course.attrs.duration|duration }}</span>
</p>
{% elseif course.model == 'live' %}
<p class="item">

View File

@ -1,8 +1,8 @@
{% if teachers %}
{% if course.teachers %}
<div class="layui-card">
<div class="layui-card-header">授课教师</div>
<div class="layui-card-body">
{% for teacher in teachers %}
{% for teacher in course.teachers %}
{% set teacher_url = url({'for':'web.user.show','id':teacher.id}) %}
<div class="sidebar-teacher-card clearfix" title="{{ teacher.about|e }}">
<div class="avatar">

View File

@ -14,6 +14,38 @@
<div class="name">{{ auth_user.name }} {{ vip_info(auth_user) }}</div>
</div>
<div class="layui-card">
<div class="layui-card-header">课程中心</div>
<div class="layui-card-body">
<ul class="my-menu">
<li><a href="{{ url({'for':'web.my.courses'}) }}">我的课程</a></li>
<li><a href="{{ url({'for':'web.my.consults'}) }}">我的咨询</a></li>
<li><a href="{{ url({'for':'web.my.favorites'}) }}">我的收藏</a></li>
<li><a href="{{ url({'for':'web.my.reviews'}) }}">我的评价</a></li>
</ul>
</div>
</div>
<div class="layui-card">
<div class="layui-card-header">订单中心</div>
<div class="layui-card-body">
<ul class="my-menu">
<li><a href="{{ url({'for':'web.my.orders'}) }}">我的订单</a></li>
<li><a href="{{ url({'for':'web.my.refunds'}) }}">我的退款</a></li>
</ul>
</div>
</div>
<div class="layui-card">
<div class="layui-card-header">聊天设置</div>
<div class="layui-card-body">
<ul class="my-menu">
<li><a href="{{ url({'for':'web.my.profile'}) }}">我的好友</a></li>
<li><a href="{{ url({'for':'web.my.account'}) }}">我的群组</a></li>
</ul>
</div>
</div>
<div class="layui-card">
<div class="layui-card-header">个人设置</div>
<div class="layui-card-body">

View File

@ -6,59 +6,39 @@
{% set status_types = {'all':'全部','pending':'待支付','finished':'已完成','closed':'已关闭','refunded':'已退款'} %}
<div class="layui-breadcrumb breadcrumb">
<a href="/">首页</a>
<a><cite>我的订单</cite></a>
</div>
<div class="wrap">
<div class="order-filter">
{% set status = request.get('status','trim','all') %}
{% for key,value in status_types %}
{% set class = (status == key) ? 'layui-btn layui-btn-sm' : 'none' %}
{% set url = (key == 'all') ? url({'for':'web.my.orders'}) : url({'for':'web.my.orders'},{'status':key}) %}
<a class="{{ class }}" href="{{ url }}">{{ value }}</a>
{% endfor %}
</div>
{% if pager.total_pages > 0 %}
<table class="layui-table order-table kg-table" lay-size="lg" lay-skin="nob">
<colgroup>
<col>
<col>
<col>
<col>
</colgroup>
<thead>
<tr>
<th>基本信息</th>
<th>订单金额</th>
<th>创建时间</th>
<th>订单状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for item in pager.items %}
{% set info_url = url({'for':'web.order.info'},{'sn':item.sn}) %}
<tr>
<td>
<p>名称:{{ item.subject }}</p>
<p>单号:{{ item.sn }}</p>
</td>
<td><span class="price">{{ '¥%0.2f'|format(item.amount) }}</span></td>
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
<td>{{ order_status(item.status) }}</td>
<td align="center">
<a class="layui-btn layui-btn-sm" href="{{ info_url }}">订单详情</a>
</td>
</tr>
<div class="layout-main">
<div class="my-sidebar">{{ partial('my/menu') }}</div>
<div class="my-content">
<div class="order-filter wrap">
{% set status = request.get('status','trim','all') %}
{% for key,value in status_types %}
{% set class = (status == key) ? 'layui-btn layui-btn-xs' : 'none' %}
{% set url = (key == 'all') ? url({'for':'web.my.orders'}) : url({'for':'web.my.orders'},{'status':key}) %}
<a class="{{ class }}" href="{{ url }}">{{ value }}</a>
{% endfor %}
</tbody>
</table>
{{ partial('partials/pager') }}
{% else %}
<div class="search-empty">未发现相关记录</div>
{% endif %}
</div>
{% if pager.total_pages > 0 %}
<div class="order-list">
{% for item in pager.items %}
<div class="order-card">
<div class="header">
<span class="sn">编号:{{ item.sn }}</span>
<span class="time">时间:{{ date('Y-m-d H:i:s',item.create_time) }}</span>
</div>
<div class="body clearfix">
<div class="column subject">{{ item.subject }}</div>
<div class="column price">{{ '¥%0.2f'|format(item.amount) }}</div>
<div class="column status">{{ order_status(item.status) }}</div>
<div class="column action">
<a class="layui-btn layui-btn-sm" href="javascript:">详情</a>
</div>
</div>
</div>
{% endfor %}
</div>
{{ partial('partials/pager') }}
{% endif %}
</div>
</div>
{% endblock %}

View File

@ -3,8 +3,8 @@
{% block content %}
<div class="layout-main">
<div class="layout-sidebar">{{ partial('my/menu') }}</div>
<div class="layout-content">
<div class="my-sidebar">{{ partial('my/menu') }}</div>
<div class="my-content">
<div class="wrap">
<div class="my-nav-title">个人信息</div>
<form class="layui-form my-form" method="post" action="{{ url({'for':'web.my.update_profile'}) }}">
@ -42,4 +42,5 @@
</div>
</div>
</div>
{% endblock %}

View File

@ -6,59 +6,39 @@
{% set status_types = {'all':'全部','pending':'待处理','canceled':'已取消','approved':'退款中','finished':'已完成'} %}
<div class="layui-breadcrumb breadcrumb">
<a href="/">首页</a>
<a><cite>我的退款</cite></a>
</div>
<div class="wrap">
<div class="order-filter">
{% set status = request.get('status','trim','all') %}
{% for key,value in status_types %}
{% set class = (status == key) ? 'layui-btn layui-btn-sm' : 'none' %}
{% set url = (key == 'all') ? url({'for':'web.my.refunds'}) : url({'for':'web.my.refunds'},{'status':key}) %}
<a class="{{ class }}" href="{{ url }}">{{ value }}</a>
{% endfor %}
</div>
{% if pager.total_pages > 0 %}
<table class="layui-table order-table kg-table" lay-size="lg" lay-skin="nob">
<colgroup>
<col>
<col>
<col>
<col>
<col>
</colgroup>
<thead>
<tr>
<th>退款项目</th>
<th>订单金额</th>
<th>退款金额</th>
<th>创建时间</th>
<th>退款状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for item in pager.items %}
{% set info_url = url({'for':'web.refund.info'},{'sn':item.sn}) %}
<tr>
<td>{{ item.subject }}</td>
<td><span class="price">{{ '¥%0.2f'|format(item.order.amount) }}</span></td>
<td><span class="price">{{ '¥%0.2f'|format(item.amount) }}</span></td>
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
<td>{{ refund_status(item.status) }}</td>
<td align="center">
<a class="layui-btn layui-btn-sm" href="{{ info_url }}">退款详情</a>
</td>
</tr>
<div class="layout-main">
<div class="my-sidebar">{{ partial('my/menu') }}</div>
<div class="my-content">
<div class="order-filter wrap">
{% set status = request.get('status','trim','all') %}
{% for key,value in status_types %}
{% set class = (status == key) ? 'layui-btn layui-btn-xs' : 'none' %}
{% set url = (key == 'all') ? url({'for':'web.my.refunds'}) : url({'for':'web.my.refunds'},{'status':key}) %}
<a class="{{ class }}" href="{{ url }}">{{ value }}</a>
{% endfor %}
</tbody>
</table>
{{ partial('partials/pager') }}
{% else %}
<div class="search-empty">未发现相关记录</div>
{% endif %}
</div>
{% if pager.total_pages > 0 %}
<div class="order-list">
{% for item in pager.items %}
<div class="order-card">
<div class="header">
<span class="sn">编号:{{ item.sn }}</span>
<span class="time">时间:{{ date('Y-m-d H:i:s',item.create_time) }}</span>
</div>
<div class="body clearfix">
<div class="column subject">{{ item.subject }}</div>
<div class="column price">{{ '¥%0.2f'|format(item.amount) }}</div>
<div class="column status">{{ refund_status(item.status) }}</div>
<div class="column action">
<a class="layui-btn layui-btn-sm" href="javascript:">详情</a>
</div>
</div>
</div>
{% endfor %}
</div>
{{ partial('partials/pager') }}
{% endif %}
</div>
</div>
{% endblock %}

View File

@ -108,7 +108,7 @@
<div class="layui-progress-bar" lay-percent="{{ item.progress }}%"></div>
</div>
</div>
<div class="duration">已学习 {{ item.duration|total_duration }}</div>
<div class="duration">已学习 {{ item.duration|duration }}</div>
</div>
</div>
{%- endmacro %}

View File

@ -1,69 +0,0 @@
<?php
namespace App\Listeners;
use App\Caches\ChapterCounter as CacheChapterCounter;
use App\Models\Chapter as ChapterModel;
use App\Services\Syncer\ChapterCounter as ChapterCounterSyncer;
use Phalcon\Events\Event;
class ChapterCounter extends Listener
{
protected $counter;
public function __construct()
{
$this->counter = new CacheChapterCounter();
}
public function incrUserCount(Event $event, $source, ChapterModel $chapter)
{
$this->counter->hIncrBy($chapter->id, 'user_count');
$this->syncChapterCounter($chapter);
}
public function decrUserCount(Event $event, $source, ChapterModel $chapter)
{
$this->counter->hDecrBy($chapter->id, 'user_count');
$this->syncChapterCounter($chapter);
}
public function incrConsultCount(Event $event, $source, ChapterModel $chapter)
{
$this->counter->hIncrBy($chapter->id, 'consult_count');
$this->syncChapterCounter($chapter);
}
public function decrConsultCount(Event $event, $source, ChapterModel $chapter)
{
$this->counter->hDecrBy($chapter->id, 'consult_count');
$this->syncChapterCounter($chapter);
}
public function incrLikeCount(Event $event, $source, ChapterModel $chapter)
{
$this->counter->hIncrBy($chapter->id, 'like_count');
$this->syncChapterCounter($chapter);
}
public function decrLikeCount(Event $event, $source, ChapterModel $chapter)
{
$this->counter->hDecrBy($chapter->id, 'like_count');
$this->syncChapterCounter($chapter);
}
protected function syncChapterCounter(ChapterModel $chapter)
{
$syncer = new ChapterCounterSyncer();
$syncer->addItem($chapter->id);
}
}

View File

@ -1,41 +0,0 @@
<?php
namespace App\Listeners;
use App\Caches\ConsultCounter as CacheConsultCounter;
use App\Models\Consult as ConsultModel;
use App\Services\Syncer\ConsultCounter as ConsultCounterSyncer;
use Phalcon\Events\Event;
class ConsultCounter extends Listener
{
protected $counter;
public function __construct()
{
$this->counter = new CacheConsultCounter();
}
public function incrLikeCount(Event $event, $source, ConsultModel $consult)
{
$this->counter->hIncrBy($consult->id, 'like_count');
$this->syncConsultCounter($consult);
}
public function decrLikeCount(Event $event, $source, ConsultModel $consult)
{
$this->counter->hDecrBy($consult->id, 'like_count');
$this->syncConsultCounter($consult);
}
protected function syncConsultCounter(ConsultModel $consult)
{
$syncer = new ConsultCounterSyncer();
$syncer->addItem($consult->id);
}
}

View File

@ -1,99 +0,0 @@
<?php
namespace App\Listeners;
use App\Caches\CourseCounter as CacheCourseCounter;
use App\Models\Course as CourseModel;
use App\Services\Syncer\CourseCounter as CourseCounterSyncer;
use App\Services\Syncer\CourseIndex as CourseIndexSyncer;
use Phalcon\Events\Event;
class CourseCounter extends Listener
{
protected $counter;
public function __construct()
{
$this->counter = new CacheCourseCounter();
}
public function incrUserCount(Event $event, $source, CourseModel $course)
{
$this->counter->hIncrBy($course->id, 'user_count');
$this->syncCourseCounter($course);
$this->syncCourseIndex($course);
}
public function decrUserCount(Event $event, $source, CourseModel $course)
{
$this->counter->hDecrBy($course->id, 'user_count');
$this->syncCourseCounter($course);
$this->syncCourseIndex($course);
}
public function incrConsultCount(Event $event, $source, CourseModel $course)
{
$this->counter->hIncrBy($course->id, 'consult_count');
$this->syncCourseCounter($course);
}
public function decrConsultCount(Event $event, $source, CourseModel $course)
{
$this->counter->hDecrBy($course->id, 'consult_count');
$this->syncCourseCounter($course);
}
public function incrReviewCount(Event $event, $source, CourseModel $course)
{
$this->counter->hIncrBy($course->id, 'review_count');
$this->syncCourseCounter($course);
$this->syncCourseIndex($course);
}
public function decrReviewCount(Event $event, $source, CourseModel $course)
{
$this->counter->hDecrBy($course->id, 'review_count');
$this->syncCourseCounter($course);
$this->syncCourseIndex($course);
}
public function incrFavoriteCount(Event $event, $source, CourseModel $course)
{
$this->counter->hIncrBy($course->id, 'favorite_count');
$this->syncCourseCounter($course);
}
public function decrFavoriteCount(Event $event, $source, CourseModel $course)
{
$this->counter->hDecrBy($course->id, 'favorite_count');
$this->syncCourseCounter($course);
}
protected function syncCourseCounter(CourseModel $course)
{
$syncer = new CourseCounterSyncer();
$syncer->addItem($course->id);
}
protected function syncCourseIndex(CourseModel $course)
{
$syncer = new CourseIndexSyncer();
$syncer->addItem($course->id);
}
}

View File

@ -1,41 +0,0 @@
<?php
namespace App\Listeners;
use App\Caches\ReviewCounter as CacheReviewCounter;
use App\Models\Review as ReviewModel;
use App\Services\Syncer\ReviewCounter as ReviewCounterSyncer;
use Phalcon\Events\Event;
class ReviewCounter extends Listener
{
protected $counter;
public function __construct()
{
$this->counter = new CacheReviewCounter();
}
public function incrLikeCount(Event $event, $source, ReviewModel $review)
{
$this->counter->hIncrBy($review->id, 'like_count');
$this->syncReviewCounter($review);
}
public function decrLikeCount(Event $event, $source, ReviewModel $review)
{
$this->counter->hDecrBy($review->id, 'like_count');
$this->syncReviewCounter($review);
}
protected function syncReviewCounter(ReviewModel $review)
{
$syncer = new ReviewCounterSyncer();
$syncer->addItem($review->id);
}
}

View File

@ -126,11 +126,11 @@ class Chapter extends Model
public $user_count;
/**
* 评论
* 咨询
*
* @var int
*/
public $comment_count;
public $consult_count;
/**
* 点赞数

View File

@ -0,0 +1,29 @@
<?php
namespace App\Services\Frontend\Chapter;
use App\Services\Frontend\ChapterTrait;
use App\Services\Frontend\CourseTrait;
use App\Services\Frontend\Service as FrontendService;
class ChapterBasicInfo extends FrontendService
{
use CourseTrait;
use ChapterTrait;
use ChapterBasicInfoTrait;
public function handle($id)
{
$chapter = $this->checkChapter($id);
$course = $this->checkCourse($chapter->course_id);
$result = $this->handleBasicInfo($chapter);
$result['course'] = $this->handleCourseInfo($course);
return $result;
}
}

View File

@ -6,24 +6,13 @@ use App\Models\Chapter as ChapterModel;
use App\Models\Course as CourseModel;
use App\Repos\Chapter as ChapterRepo;
use App\Services\ChapterVod as ChapterVodService;
use App\Services\Frontend\ChapterTrait;
use App\Services\Frontend\Service as FrontendService;
use App\Services\Live as LiveService;
use WhichBrowser\Parser as BrowserParser;
class ChapterInfoBasic extends FrontendService
trait ChapterBasicInfoTrait
{
use ChapterTrait;
public function handle($id)
{
$chapter = $this->checkChapterCache($id);
return $this->handleChapter($chapter);
}
protected function handleChapter(ChapterModel $chapter)
protected function handleBasicInfo(ChapterModel $chapter)
{
$result = [];
@ -42,6 +31,15 @@ class ChapterInfoBasic extends FrontendService
return $result;
}
protected function handleCourseInfo(CourseModel $course)
{
return [
'id' => $course->id,
'title' => $course->title,
'cover' => $course->cover,
];
}
protected function formatChapterVod(ChapterModel $chapter)
{
$chapterVodService = new ChapterVodService();
@ -56,7 +54,6 @@ class ChapterInfoBasic extends FrontendService
'play_urls' => $playUrls,
'user_count' => $chapter->user_count,
'like_count' => $chapter->like_count,
'comment_count' => $chapter->comment_count,
];
}
@ -88,7 +85,6 @@ class ChapterInfoBasic extends FrontendService
'end_time' => $live->end_time,
'user_count' => $chapter->user_count,
'like_count' => $chapter->like_count,
'comment_count' => $chapter->comment_count,
];
}
@ -106,7 +102,6 @@ class ChapterInfoBasic extends FrontendService
'content' => $read->content,
'user_count' => $chapter->user_count,
'like_count' => $chapter->like_count,
'comment_count' => $chapter->comment_count,
];
}

View File

@ -7,13 +7,10 @@ use App\Models\ChapterUser as ChapterUserModel;
use App\Models\Course as CourseModel;
use App\Models\CourseUser as CourseUserModel;
use App\Models\User as UserModel;
use App\Repos\Chapter as ChapterRepo;
use App\Repos\ChapterLike as ChapterLikeRepo;
use App\Services\ChapterVod as ChapterVodService;
use App\Services\Frontend\ChapterTrait;
use App\Services\Frontend\CourseTrait;
use App\Services\Frontend\Service as FrontendService;
use App\Services\Live as LiveService;
class ChapterInfo extends FrontendService
{
@ -30,12 +27,13 @@ class ChapterInfo extends FrontendService
use CourseTrait;
use ChapterTrait;
use ChapterBasicInfoTrait;
public function handle($id)
{
$chapter = $this->checkChapterCache($id);
$chapter = $this->checkChapter($id);
$course = $this->checkCourseCache($chapter->course_id);
$course = $this->checkCourse($chapter->course_id);
$this->course = $course;
@ -54,9 +52,9 @@ class ChapterInfo extends FrontendService
protected function handleChapter(ChapterModel $chapter, UserModel $user)
{
$result = $this->formatChapter($chapter);
$result = $this->handleBasicInfo($chapter);
$result['course'] = $this->handleCourse($this->course);
$result['course'] = $this->handleCourseInfo($this->course);
$me = [
'plan_id' => 0,
@ -93,109 +91,6 @@ class ChapterInfo extends FrontendService
return $result;
}
protected function handleCourse(CourseModel $course)
{
return [
'id' => $course->id,
'title' => $course->title,
'cover' => $course->cover,
];
}
protected function formatChapter(ChapterModel $chapter)
{
$item = [];
switch ($chapter->model) {
case CourseModel::MODEL_VOD:
$item = $this->formatChapterVod($chapter);
break;
case CourseModel::MODEL_LIVE:
$item = $this->formatChapterLive($chapter);
break;
case CourseModel::MODEL_READ:
$item = $this->formatChapterRead($chapter);
break;
}
return $item;
}
protected function formatChapterVod(ChapterModel $chapter)
{
$service = new ChapterVodService();
$playUrls = $service->getPlayUrls($chapter->id);
return [
'id' => $chapter->id,
'title' => $chapter->title,
'summary' => $chapter->summary,
'model' => $chapter->model,
'play_urls' => $playUrls,
'user_count' => $chapter->user_count,
'like_count' => $chapter->like_count,
'consult_count' => $chapter->consult_count,
];
}
protected function formatChapterLive(ChapterModel $chapter)
{
$service = new LiveService();
$streamName = $this->getLiveStreamName($chapter->id);
$chapterRepo = new ChapterRepo();
$live = $chapterRepo->findChapterLive($chapter->id);
$playUrls = [];
if ($live->start_time - time() > 1800) {
$status = 'pending';
} elseif (time() - $live->end_time > 1800) {
$status = 'finished';
} else {
$status = $service->getStreamState($streamName);
}
if ($status == 'active') {
$playUrls = $service->getPullUrls($streamName);
}
return [
'id' => $chapter->id,
'title' => $chapter->title,
'summary' => $chapter->summary,
'model' => $chapter->model,
'status' => $status,
'start_time' => $live->start_time,
'end_time' => $live->end_time,
'play_urls' => $playUrls,
'user_count' => $chapter->user_count,
'like_count' => $chapter->like_count,
'consult_count' => $chapter->consult_count,
];
}
protected function formatChapterRead(ChapterModel $chapter)
{
$chapterRepo = new ChapterRepo();
$read = $chapterRepo->findChapterRead($chapter->id);
return [
'id' => $chapter->id,
'title' => $chapter->title,
'summary' => $chapter->summary,
'model' => $chapter->model,
'content' => $read->content,
'user_count' => $chapter->user_count,
'like_count' => $chapter->like_count,
'consult_count' => $chapter->consult_count,
];
}
protected function handleCourseUser(CourseModel $course, UserModel $user)
{
if ($user->id == 0) return;
@ -247,11 +142,6 @@ class ChapterInfo extends FrontendService
$this->incrChapterUserCount($chapter);
}
protected function getVodPosition(ChapterModel $chapter, UserModel $user)
{
}
protected function getLiveStreamName($id)
{
return "chapter_{$id}";
@ -259,12 +149,16 @@ class ChapterInfo extends FrontendService
protected function incrCourseUserCount(CourseModel $course)
{
$this->eventsManager->fire('courseCounter:incrUserCount', $this, $course);
$course->user_count += 1;
$course->update();
}
protected function incrChapterUserCount(ChapterModel $chapter)
{
$this->eventsManager->fire('chapterCounter:incrUserCount', $this, $chapter);
$chapter->user_count += 1;
$chapter->update();
}
}

View File

@ -9,7 +9,6 @@ use App\Repos\ChapterLike as ChapterLikeRepo;
use App\Services\Frontend\ChapterTrait;
use App\Services\Frontend\Service as FrontendService;
use App\Validators\UserDailyLimit as UserDailyLimitValidator;
use Phalcon\Events\Manager as EventsManager;
class ChapterLike extends FrontendService
{
@ -64,25 +63,21 @@ class ChapterLike extends FrontendService
protected function incrLikeCount(ChapterModel $chapter)
{
$this->getPhEventsManager()->fire('chapterCounter:incrLikeCount', $this, $chapter);
$chapter->like_count += 1;
$chapter->update();
}
protected function decrLikeCount(ChapterModel $chapter)
{
$this->getPhEventsManager()->fire('chapterCounter:decrLikeCount', $this, $chapter);
$chapter->like_count -= 1;
$chapter->update();
}
protected function incrUserDailyChapterLikeCount(UserModel $user)
{
$this->getPhEventsManager()->fire('userDailyCounter:incrChapterLikeCount', $this, $user);
}
/**
* @return EventsManager
*/
protected function getPhEventsManager()
{
return $this->getDI()->get('eventsManager');
$this->eventsManager->fire('userDailyCounter:incrChapterLikeCount', $this, $user);
}
}

View File

@ -1,75 +0,0 @@
<?php
namespace App\Services\Frontend\Chapter;
use App\Builders\CommentList as CommentListBuilder;
use App\Library\Paginator\Query as PagerQuery;
use App\Repos\Comment as CommentRepo;
use App\Services\Frontend\ChapterTrait;
use App\Services\Frontend\Service as FrontendService;
class CommentList extends FrontendService
{
use ChapterTrait;
public function handle($chapterId)
{
$chapter = $this->checkChapter($chapterId);
$pagerQuery = new PagerQuery();
$params = $pagerQuery->getParams();
$params['chapter_id'] = $chapter->id;
$params['published'] = 1;
$params['deleted'] = 0;
$sort = $pagerQuery->getSort();
$page = $pagerQuery->getPage();
$limit = $pagerQuery->getLimit();
$commentRepo = new CommentRepo();
$pager = $commentRepo->paginate($params, $sort, $page, $limit);
return $this->handleComments($pager);
}
protected function handleComments($pager)
{
if ($pager->total_items == 0) {
return $pager;
}
$comments = $pager->items->toArray();
$builder = new CommentListBuilder();
$users = $builder->getUsers($comments);
$items = [];
foreach ($comments as $comment) {
$user = $users[$comment['user_id']] ?? new \stdClass();
$comment['mentions'] = $comment['mentions'] ? json_decode($comment['mentions']) : [];
$items[] = [
'id' => $comment['id'],
'content' => $comment['content'],
'mentions' => $comment['mentions'],
'like_count' => $comment['like_count'],
'reply_count' => $comment['reply_count'],
'create_time' => $comment['create_time'],
'user' => $user,
];
}
$pager->items = $items;
return $pager;
}
}

View File

@ -52,7 +52,9 @@ class ConsultCreate extends FrontendService
$consult->create();
$this->incrCourseConsultCount($course);
$this->incrChapterConsultCount($chapter);
$this->incrUserDailyConsultCount($user);
return $consult;
@ -76,12 +78,16 @@ class ConsultCreate extends FrontendService
protected function incrCourseConsultCount(CourseModel $course)
{
$this->eventsManager->fire('courseCounter:incrConsultCount', $this, $course);
$course->consult_count += 1;
$course->update();
}
protected function incrChapterConsultCount(ChapterModel $chapter)
{
$this->eventsManager->fire('chapterCounter:incrConsultCount', $this, $chapter);
$chapter->consult_count += 1;
$chapter->update();
}
protected function incrUserDailyConsultCount(UserModel $user)

View File

@ -2,7 +2,9 @@
namespace App\Services\Frontend\Consult;
use App\Models\Chapter as ChapterModel;
use App\Models\Course as CourseModel;
use App\Services\Frontend\ChapterTrait;
use App\Services\Frontend\ConsultTrait;
use App\Services\Frontend\CourseTrait;
use App\Services\Frontend\Service as FrontendService;
@ -11,8 +13,9 @@ use App\Validators\Consult as ConsultValidator;
class ConsultDelete extends FrontendService
{
use ConsultTrait;
use CourseTrait;
use ChapterTrait;
use ConsultTrait;
public function handle($id)
{
@ -20,20 +23,33 @@ class ConsultDelete extends FrontendService
$course = $this->checkCourse($consult->course_id);
$chapter = $this->checkChapter($consult->chapter_id);
$user = $this->getLoginUser();
$validator = new ConsultValidator();
$validator->checkOwner($user->id, $consult->user_id);
$consult->delete();
$consult->update(['deleted' => 1]);
$this->decrCourseConsultCount($course);
$this->decrChapterConsultCount($chapter);
}
protected function decrCourseConsultCount(CourseModel $course)
{
$this->eventsManager->fire('courseCounter:decrConsultCount', $this, $course);
$course->consult_count -= 1;
$course->update();
}
protected function decrChapterConsultCount(ChapterModel $chapter)
{
$chapter->consult_count -= 1;
$chapter->update();
}
}

View File

@ -9,7 +9,6 @@ use App\Services\Frontend\ConsultTrait;
use App\Services\Frontend\Service as FrontendService;
use App\Validators\Consult as ConsultValidator;
use App\Validators\UserDailyLimit as UserDailyLimitValidator;
use Phalcon\Events\Manager as EventsManager;
class ConsultLike extends FrontendService
{
@ -64,25 +63,21 @@ class ConsultLike extends FrontendService
protected function incrLikeCount(ConsultModel $consult)
{
$this->getPhEventsManager()->fire('consultCounter:incrLikeCount', $this, $consult);
$consult->like_count += 1;
$consult->update();
}
protected function decrLikeCount(ConsultModel $consult)
{
$this->getPhEventsManager()->fire('consultCounter:decrLikeCount', $this, $consult);
$consult->like_count -= 1;
$consult->update();
}
protected function incrUserDailyConsultLikeCount(UserModel $user)
{
$this->getPhEventsManager()->fire('userDailyCounter:incrConsultLikeCount', $this, $user);
}
/**
* @return EventsManager
*/
protected function getPhEventsManager()
{
return $this->getDI()->get('eventsManager');
$this->eventsManager->fire('userDailyCounter:incrConsultLikeCount', $this, $user);
}
}

View File

@ -3,14 +3,12 @@
namespace App\Services\Frontend\Consult;
use App\Services\Frontend\ConsultTrait;
use App\Services\Frontend\CourseTrait;
use App\Services\Frontend\Service as FrontendService;
use App\Validators\Consult as ConsultValidator;
class ConsultUpdate extends FrontendService
{
use CourseTrait;
use ConsultTrait;
public function handle($id)

View File

@ -0,0 +1,21 @@
<?php
namespace App\Services\Frontend\Course;
use App\Services\Frontend\CourseTrait;
use App\Services\Frontend\Service as FrontendService;
class CourseBasicInfo extends FrontendService
{
use CourseTrait;
use CourseBasicInfoTrait;
public function handle($id)
{
$course = $this->checkCourse($id);
return $this->handleBasicInfo($course);
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace App\Services\Frontend\Course;
use App\Caches\CourseTeacherList as CourseTeacherListCache;
use App\Http\Web\Services\CourseQuery as CourseQueryService;
use App\Models\Course as CourseModel;
use App\Repos\Course as CourseRepo;
trait CourseBasicInfoTrait
{
protected function handleBasicInfo(CourseModel $course)
{
$categoryPaths = $this->handleCategoryPaths($course);
$teachers = $this->handleTeachers($course);
$ratings = $this->handleRatings($course);
return [
'id' => $course->id,
'title' => $course->title,
'cover' => $course->cover,
'summary' => $course->summary,
'details' => $course->details,
'keywords' => $course->keywords,
'market_price' => $course->market_price,
'vip_price' => $course->vip_price,
'study_expiry' => $course->study_expiry,
'refund_expiry' => $course->refund_expiry,
'category_paths' => $categoryPaths,
'teachers' => $teachers,
'ratings' => $ratings,
'model' => $course->model,
'level' => $course->level,
'attrs' => $course->attrs,
'user_count' => $course->user_count,
'lesson_count' => $course->lesson_count,
'package_count' => $course->package_count,
'review_count' => $course->review_count,
'consult_count' => $course->consult_count,
'favorite_count' => $course->favorite_count,
];
}
protected function handleCategoryPaths(CourseModel $course)
{
$service = new CourseQueryService();
return $service->handleCategoryPaths($course->category_id);
}
protected function handleRatings(CourseModel $course)
{
$repo = new CourseRepo();
$rating = $repo->findCourseRating($course->id);
return [
'rating' => $rating->rating,
'rating1' => $rating->rating1,
'rating2' => $rating->rating2,
'rating3' => $rating->rating3,
];
}
protected function handleTeachers(CourseModel $course)
{
$cache = new CourseTeacherListCache();
$result = $cache->get($course->id);
return $result ?: [];
}
}

View File

@ -4,7 +4,6 @@ namespace App\Services\Frontend\Course;
use App\Models\Course as CourseModel;
use App\Models\User as UserModel;
use App\Repos\Course as CourseRepo;
use App\Repos\CourseFavorite as CourseFavoriteRepo;
use App\Services\Frontend\CourseTrait;
use App\Services\Frontend\Service as FrontendService;
@ -13,10 +12,11 @@ class CourseInfo extends FrontendService
{
use CourseTrait;
use CourseBasicInfoTrait;
public function handle($id)
{
$course = $this->checkCourseCache($id);
$course = $this->checkCourse($id);
$user = $this->getCurrentUser();
@ -27,41 +27,7 @@ class CourseInfo extends FrontendService
protected function handleCourse(CourseModel $course, UserModel $user)
{
$repo = new CourseRepo();
$rating = $repo->findCourseRating($course->id);
$ratings = [
'rating' => $rating->rating,
'rating1' => $rating->rating1,
'rating2' => $rating->rating2,
'rating3' => $rating->rating3,
];
$result = [
'id' => $course->id,
'title' => $course->title,
'cover' => $course->cover,
'summary' => $course->summary,
'details' => $course->details,
'keywords' => $course->keywords,
'category_id' => $course->category_id,
'teacher_id' => $course->teacher_id,
'market_price' => $course->market_price,
'vip_price' => $course->vip_price,
'study_expiry' => $course->study_expiry,
'refund_expiry' => $course->refund_expiry,
'ratings' => $ratings,
'model' => $course->model,
'level' => $course->level,
'attrs' => $course->attrs,
'user_count' => $course->user_count,
'lesson_count' => $course->lesson_count,
'package_count' => $course->package_count,
'review_count' => $course->review_count,
'consult_count' => $course->consult_count,
'favorite_count' => $course->favorite_count,
];
$result = $this->handleBasicInfo($course);
$me = [
'plan_id' => 0,

View File

@ -1,48 +0,0 @@
<?php
namespace App\Services\Frontend\Course;
use App\Models\Course as CourseModel;
use App\Services\Frontend\CourseTrait;
use App\Services\Frontend\Service as FrontendService;
class CourseInfoBasic extends FrontendService
{
use CourseTrait;
public function handle($id)
{
$course = $this->checkCourseCache($id);
return $this->handleCourse($course);
}
protected function handleCourse(CourseModel $course)
{
return [
'id' => $course->id,
'title' => $course->title,
'cover' => $course->cover,
'summary' => $course->summary,
'details' => $course->details,
'keywords' => $course->keywords,
'market_price' => $course->market_price,
'vip_price' => $course->vip_price,
'study_expiry' => $course->study_expiry,
'refund_expiry' => $course->refund_expiry,
'rating' => $course->rating,
'model' => $course->model,
'level' => $course->level,
'attrs' => $course->attrs,
'user_count' => $course->user_count,
'lesson_count' => $course->lesson_count,
'package_count' => $course->package_count,
'review_count' => $course->review_count,
'comment_count' => $course->comment_count,
'consult_count' => $course->consult_count,
'favorite_count' => $course->favorite_count,
];
}
}

View File

@ -5,8 +5,8 @@ namespace App\Services\Frontend\Review;
use App\Models\Course as CourseModel;
use App\Models\Review as ReviewModel;
use App\Models\User as UserModel;
use App\Repos\CourseRating as CourseRatingRepo;
use App\Services\Frontend\CourseTrait;
use App\Services\Frontend\ReviewTrait;
use App\Services\Frontend\Service as FrontendService;
use App\Validators\CourseUser as CourseUserValidator;
use App\Validators\Review as ReviewValidator;
@ -16,6 +16,7 @@ class ReviewCreate extends FrontendService
{
use CourseTrait;
use ReviewTrait;
public function handle()
{
@ -36,14 +37,15 @@ class ReviewCreate extends FrontendService
$validator = new ReviewValidator();
$data = [];
$data = [
'course_id' => $course->id,
'user_id' => $user->id,
];
$data['content'] = $validator->checkContent($post['content']);
$data['rating1'] = $validator->checkRating($post['rating1']);
$data['rating2'] = $validator->checkRating($post['rating2']);
$data['rating3'] = $validator->checkRating($post['rating3']);
$data['course_id'] = $course->id;
$data['user_id'] = $user->id;
$review = new ReviewModel();
@ -58,25 +60,11 @@ class ReviewCreate extends FrontendService
return $review;
}
protected function updateCourseRating(CourseModel $course)
{
$repo = new CourseRatingRepo();
$courseRating = $repo->findByCourseId($course->id);
$courseRating->rating = $repo->averageRating($course->id);
$courseRating->rating1 = $repo->averageRating1($course->id);
$courseRating->rating2 = $repo->averageRating2($course->id);
$courseRating->rating3 = $repo->averageRating3($course->id);
$courseRating->update();
$course->rating = $courseRating->rating;
$course->update();
}
protected function incrCourseReviewCount(CourseModel $course)
{
$this->eventsManager->fire('courseCounter:incrReviewCount', $this, $course);
$course->review_count += 1;
$course->update();
}
protected function incrUserDailyReviewCount(UserModel $user)

View File

@ -18,7 +18,7 @@ class ReviewDelete extends FrontendService
{
$review = $this->checkReview($id);
$course = $this->checkCourseCache($review->course_id);
$course = $this->checkCourse($review->course_id);
$user = $this->getLoginUser();
@ -29,11 +29,15 @@ class ReviewDelete extends FrontendService
$review->delete();
$this->decrCourseReviewCount($course);
$this->updateCourseRating($course);
}
protected function decrCourseReviewCount(CourseModel $course)
{
$this->eventsManager->fire('courseCounter:decrReviewCount', $this, $course);
$course->review_count -= 1;
$course->update();
}
}

View File

@ -9,7 +9,6 @@ use App\Services\Frontend\ReviewTrait;
use App\Services\Frontend\Service as FrontendService;
use App\Validators\Review as ReviewValidator;
use App\Validators\UserDailyLimit as UserDailyLimitValidator;
use Phalcon\Events\Manager as EventsManager;
class ReviewLike extends FrontendService
{
@ -64,25 +63,21 @@ class ReviewLike extends FrontendService
protected function incrLikeCount(ReviewModel $review)
{
$this->getPhEventsManager()->fire('reviewCounter:incrLikeCount', $this, $review);
$review->like_count += 1;
$review->update();
}
protected function decrLikeCount(ReviewModel $review)
{
$this->getPhEventsManager()->fire('reviewCounter:decrLikeCount', $this, $review);
$review->like_count -= 1;
$review->update();
}
protected function incrUserDailyReviewLikeCount(UserModel $user)
{
$this->getPhEventsManager()->fire('userDailyCounter:incrReviewLikeCount', $this, $user);
}
/**
* @return EventsManager
*/
protected function getPhEventsManager()
{
return $this->getDI()->get('eventsManager');
$this->eventsManager->fire('userDailyCounter:incrReviewLikeCount', $this, $user);
}
}

View File

@ -19,18 +19,24 @@ class ReviewUpdate extends FrontendService
$review = $this->checkReview($id);
$course = $this->checkCourse($review->course_id);
$user = $this->getLoginUser();
$validator = new ReviewValidator();
$validator->checkOwner($user->id, $review->user_id);
$content = $validator->checkContent($post['content']);
$rating = $validator->checkRating($post['rating']);
$data = [];
$review->content = $content;
$review->rating = $rating;
$review->update();
$data['content'] = $validator->checkContent($post['content']);
$data['rating1'] = $validator->checkRating($post['rating1']);
$data['rating2'] = $validator->checkRating($post['rating2']);
$data['rating3'] = $validator->checkRating($post['rating3']);
$review->update($data);
$this->updateCourseRating($course);
}
}

View File

@ -2,6 +2,8 @@
namespace App\Services\Frontend;
use App\Models\Course as CourseModel;
use App\Repos\CourseRating as CourseRatingRepo;
use App\Validators\Review as ReviewValidator;
trait ReviewTrait
@ -14,4 +16,22 @@ trait ReviewTrait
return $validator->checkReview($id);
}
public function updateCourseRating(CourseModel $course)
{
$repo = new CourseRatingRepo();
$courseRating = $repo->findByCourseId($course->id);
$courseRating->rating = $repo->averageRating($course->id);
$courseRating->rating1 = $repo->averageRating1($course->id);
$courseRating->rating2 = $repo->averageRating2($course->id);
$courseRating->rating3 = $repo->averageRating3($course->id);
$courseRating->update();
$course->rating = $courseRating->rating;
$course->update();
}
}

View File

@ -84,7 +84,6 @@ class CourseDocument extends Component
'teacher' => $teacher,
'user_count' => $course->user_count,
'lesson_count' => $course->lesson_count,
'comment_count' => $course->comment_count,
'consult_count' => $course->consult_count,
'review_count' => $course->review_count,
'favorite_count' => $course->favorite_count,

View File

@ -1,47 +0,0 @@
<?php
namespace App\Services\Syncer;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Services\Service;
class ChapterCounter extends Service
{
/**
* @var RedisCache
*/
protected $cache;
/**
* @var \Redis
*/
protected $redis;
/**
* @var int
*/
protected $lifetime = 86400;
public function __construct()
{
$this->cache = $this->getDI()->get('cache');
$this->redis = $this->cache->getRedis();
}
public function addItem($chapterId)
{
$key = $this->getSyncKey();
$this->redis->sAdd($key, $chapterId);
$this->redis->expire($key, $this->lifetime);
}
public function getSyncKey()
{
return 'chapter_counter_sync';
}
}

View File

@ -1,47 +0,0 @@
<?php
namespace App\Services\Syncer;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Services\Service;
class CommentCounter extends Service
{
/**
* @var RedisCache
*/
protected $cache;
/**
* @var \Redis
*/
protected $redis;
/**
* @var int
*/
protected $lifetime = 86400;
public function __construct()
{
$this->cache = $this->getDI()->get('cache');
$this->redis = $this->cache->getRedis();
}
public function addItem($commentId)
{
$key = $this->getSyncKey();
$this->redis->sAdd($key, $commentId);
$this->redis->expire($key, $this->lifetime);
}
public function getSyncKey()
{
return 'comment_counter_sync';
}
}

View File

@ -1,47 +0,0 @@
<?php
namespace App\Services\Syncer;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Services\Service;
class ConsultCounter extends Service
{
/**
* @var RedisCache
*/
protected $cache;
/**
* @var \Redis
*/
protected $redis;
/**
* @var int
*/
protected $lifetime = 86400;
public function __construct()
{
$this->cache = $this->getDI()->get('cache');
$this->redis = $this->cache->getRedis();
}
public function addItem($consultId)
{
$key = $this->getSyncKey();
$this->redis->sAdd($key, $consultId);
$this->redis->expire($key, $this->lifetime);
}
public function getSyncKey()
{
return 'consult_counter_sync';
}
}

View File

@ -1,47 +0,0 @@
<?php
namespace App\Services\Syncer;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Services\Service;
class CourseCounter extends Service
{
/**
* @var RedisCache
*/
protected $cache;
/**
* @var \Redis
*/
protected $redis;
/**
* @var int
*/
protected $lifetime = 86400;
public function __construct()
{
$this->cache = $this->getDI()->get('cache');
$this->redis = $this->cache->getRedis();
}
public function addItem($courseId)
{
$key = $this->getSyncKey();
$this->redis->sAdd($key, $courseId);
$this->redis->expire($key, $this->lifetime);
}
public function getSyncKey()
{
return 'course_counter_sync';
}
}

View File

@ -1,47 +0,0 @@
<?php
namespace App\Services\Syncer;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Services\Service;
class ReviewCounter extends Service
{
/**
* @var RedisCache
*/
protected $cache;
/**
* @var \Redis
*/
protected $redis;
/**
* @var int
*/
protected $lifetime = 86400;
public function __construct()
{
$this->cache = $this->getDI()->get('cache');
$this->redis = $this->cache->getRedis();
}
public function addItem($reviewId)
{
$key = $this->getSyncKey();
$this->redis->sAdd($key, $reviewId);
$this->redis->expire($key, $this->lifetime);
}
public function getSyncKey()
{
return 'review_counter_sync';
}
}

View File

@ -1,19 +1,11 @@
<?php
use App\Listeners\ChapterCounter;
use App\Listeners\ConsultCounter;
use App\Listeners\CourseCounter;
use App\Listeners\Pay;
use App\Listeners\Profiler;
use App\Listeners\ReviewCounter;
use App\Listeners\UserDailyCounter;
return [
'db' => Profiler::class,
'pay' => Pay::class,
'courseCounter' => CourseCounter::class,
'chapterCounter' => ChapterCounter::class,
'consultCounter' => ConsultCounter::class,
'reviewCounter' => ReviewCounter::class,
'userDailyCounter' => UserDailyCounter::class,
];

View File

@ -1327,6 +1327,16 @@ body {
cursor: pointer;
}
.my-sidebar {
float: left;
width: 220px;
}
.my-content {
float: right;
width: 900px;
}
.my-profile-card {
text-align: center;
}
@ -1336,8 +1346,8 @@ body {
}
.my-profile-card .avatar img {
width: 96px;
height: 96px;
width: 90px;
height: 90px;
border-radius: 100px;
}
@ -1347,7 +1357,7 @@ body {
.my-menu li {
line-height: 30px;
text-align: center;
padding-left: 30px;
}
.my-nav-title {
@ -1388,8 +1398,7 @@ body {
}
.order-filter {
line-height: 40px;
margin-bottom: 20px;
padding: 15px;
}
.order-filter a {
@ -1404,20 +1413,56 @@ body {
color: red;
}
.order-item {
.order-card {
padding: 15px;
margin-bottom: 20px;
background-color: white;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
}
.order-card .header {
padding-bottom: 10px;
margin-bottom: 10px;
border-bottom: 1px solid #e6e6e6;
}
.order-item:last-child {
padding-bottom: 0;
margin-bottom: 0;
border-bottom: none;
.order-card .header span {
margin-right: 10px;
}
.order-item span {
margin-right: 8px;
.order-card .header .sn {
color: #666;
}
.order-card .header .time {
color: #666;
}
.order-card .body {
}
.order-card .column {
float: left;
line-height: 40px;
}
.order-card .subject {
width: 50%;
color: #666;
}
.order-card .price {
width: 20%;
color: red;
}
.order-card .status {
width: 20%;
color: #666;
}
.order-card .action {
width: 10%;
}
.im-search-wrap {

View File

@ -3,6 +3,9 @@ layui.use(['jquery', 'helper'], function () {
var $ = layui.jquery;
var helper = layui.helper;
/**
* 点赞
*/
$('.icon-praise').on('click', function () {
var $this = $(this);
var $parent = $this.parent();
@ -29,4 +32,19 @@ layui.use(['jquery', 'helper'], function () {
});
});
/**
* 咨询
*/
$('.icon-help').on('click', function () {
var url = $(this).parent().data('url');
helper.checkLogin(function () {
layer.open({
type: 2,
title: '课程咨询',
content: [url, 'no'],
area: ['640px', '300px']
});
});
});
});

View File

@ -1,21 +0,0 @@
layui.use(['jquery', 'helper'], function () {
var $ = layui.jquery;
var helper = layui.helper;
/**
* 咨询
*/
$('.icon-help').on('click', function () {
var url = $(this).parent().data('url');
helper.checkLogin(function () {
layer.open({
type: 2,
title: '课程咨询',
content: [url, 'no'],
area: ['640px', '300px']
});
});
});
});

View File

@ -121,11 +121,6 @@ layui.use(['jquery', 'layer', 'helper'], function () {
helper.ajaxLoadHtml($tabReviews.data('url'), $tabReviews.attr('id'));
}
if ($('#sidebar-teachers').length > 0) {
var $sdTeachers = $('#sidebar-teachers');
helper.ajaxLoadHtml($sdTeachers.data('url'), $sdTeachers.attr('id'));
}
if ($('#sidebar-topics').length > 0) {
var $sdTopics = $('#sidebar-topics');
helper.ajaxLoadHtml($sdTopics.data('url'), $sdTopics.attr('id'));

View File

@ -40,9 +40,6 @@ $scheduler->php($script, $bin, ['--task' => 'sync_course_counter', '--action' =>
$scheduler->php($script, $bin, ['--task' => 'sync_chapter_counter', '--action' => 'main'])
->hourly(17);
$scheduler->php($script, $bin, ['--task' => 'sync_comment_counter', '--action' => 'main'])
->hourly(19);
$scheduler->php($script, $bin, ['--task' => 'sync_consult_counter', '--action' => 'main'])
->hourly(23);