mirror of
https://gitee.com/koogua/course-tencent-cloud.git
synced 2025-08-03 04:55:53 +08:00
整理功能
This commit is contained in:
parent
ab27040f2f
commit
ac51d23934
@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Repos\Topic as TopicRepo;
|
||||
|
||||
class TopicCourseList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "topic_course_list:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$topicRepo = new TopicRepo();
|
||||
|
||||
$courses = $topicRepo->findCourses($id);
|
||||
|
||||
if ($courses->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->handleContent($courses);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CourseModel[] $courses
|
||||
* @return array
|
||||
*/
|
||||
public function handleContent($courses)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
|
||||
}
|
@ -23,12 +23,10 @@ class UserDailyCounter extends Counter
|
||||
{
|
||||
return [
|
||||
'favorite_count' => 0,
|
||||
'comment_count' => 0,
|
||||
'danmu_count' => 0,
|
||||
'consult_count' => 0,
|
||||
'order_count' => 0,
|
||||
'chapter_like_count' => 0,
|
||||
'comment_like_count' => 0,
|
||||
'consult_like_count' => 0,
|
||||
'review_like_count' => 0,
|
||||
];
|
||||
|
@ -16,7 +16,8 @@ class Controller extends \Phalcon\Mvc\Controller
|
||||
*/
|
||||
protected $authUser;
|
||||
|
||||
use ResponseTrait, SecurityTrait;
|
||||
use ResponseTrait;
|
||||
use SecurityTrait;
|
||||
|
||||
public function beforeExecuteRoute(Dispatcher $dispatcher)
|
||||
{
|
||||
|
@ -14,7 +14,9 @@ use App\Traits\Security as SecurityTrait;
|
||||
class SessionController extends \Phalcon\Mvc\Controller
|
||||
{
|
||||
|
||||
use AuthTrait, ResponseTrait, SecurityTrait;
|
||||
use AuthTrait;
|
||||
use ResponseTrait;
|
||||
use SecurityTrait;
|
||||
|
||||
/**
|
||||
* @Route("/login", name="admin.login")
|
||||
|
@ -9,7 +9,8 @@ use Phalcon\Mvc\Dispatcher;
|
||||
class Controller extends \Phalcon\Mvc\Controller
|
||||
{
|
||||
|
||||
use ResponseTrait, SecurityTrait;
|
||||
use ResponseTrait;
|
||||
use SecurityTrait;
|
||||
|
||||
public function beforeExecuteRoute(Dispatcher $dispatcher)
|
||||
{
|
||||
|
@ -9,7 +9,8 @@ use Phalcon\Mvc\Dispatcher;
|
||||
class Controller extends \Phalcon\Mvc\Controller
|
||||
{
|
||||
|
||||
use ResponseTrait, SecurityTrait;
|
||||
use ResponseTrait;
|
||||
use SecurityTrait;
|
||||
|
||||
public function beforeExecuteRoute(Dispatcher $dispatcher)
|
||||
{
|
||||
|
@ -34,7 +34,8 @@ class Controller extends \Phalcon\Mvc\Controller
|
||||
*/
|
||||
protected $authUser;
|
||||
|
||||
use ResponseTrait, SecurityTrait;
|
||||
use ResponseTrait;
|
||||
use SecurityTrait;
|
||||
|
||||
public function beforeExecuteRoute(Dispatcher $dispatcher)
|
||||
{
|
||||
|
@ -16,7 +16,8 @@ class LayerController extends \Phalcon\Mvc\Controller
|
||||
*/
|
||||
protected $authUser;
|
||||
|
||||
use ResponseTrait, SecurityTrait;
|
||||
use ResponseTrait;
|
||||
use SecurityTrait;
|
||||
|
||||
public function beforeExecuteRoute(Dispatcher $dispatcher)
|
||||
{
|
||||
|
@ -14,7 +14,8 @@ use PHPQRCode\QRcode as PHPQRCode;
|
||||
class PublicController extends \Phalcon\Mvc\Controller
|
||||
{
|
||||
|
||||
use ResponseTrait, SecurityTrait;
|
||||
use ResponseTrait;
|
||||
use SecurityTrait;
|
||||
|
||||
/**
|
||||
* @Get("/content/img/{id:[0-9]+}", name="web.content_img")
|
||||
|
@ -31,7 +31,8 @@ use GatewayClient\Gateway;
|
||||
class Im extends Service
|
||||
{
|
||||
|
||||
use ImFriendTrait, ImGroupTrait;
|
||||
use ImFriendTrait;
|
||||
use ImGroupTrait;
|
||||
|
||||
public function init()
|
||||
{
|
||||
|
@ -1,9 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Web\Services;
|
||||
|
||||
class Order extends Service
|
||||
{
|
||||
|
||||
|
||||
}
|
15
app/Http/Web/Views/chapter/breadcrumb.volt
Normal file
15
app/Http/Web/Views/chapter/breadcrumb.volt
Normal file
@ -0,0 +1,15 @@
|
||||
<div class="breadcrumb">
|
||||
<span class="layui-breadcrumb">
|
||||
<a class="kg-back" href="javascript:"><i class="layui-icon layui-icon-return"></i> 返回课程</a>
|
||||
<a><cite>{{ chapter.course.title }}</cite></a>
|
||||
<a><cite>{{ chapter.title }}</cite></a>
|
||||
</span>
|
||||
<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="分享到微信"><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>
|
||||
</span>
|
||||
</div>
|
@ -3,6 +3,7 @@
|
||||
{% block content %}
|
||||
|
||||
{% set chapter_full_url = full_url({'for':'web.chapter.show','id':chapter.id}) %}
|
||||
{% set course_url = url({'for':'web.course.show','id':chapter.course.id}) %}
|
||||
{% set learning_url = url({'for':'web.chapter.learning','id':chapter.id}) %}
|
||||
{% set live_chats_url = url({'for':'web.live.chats','id':chapter.id}) %}
|
||||
{% set live_stats_url = url({'for':'web.live.stats','id':chapter.id}) %}
|
||||
@ -13,6 +14,7 @@
|
||||
|
||||
<div class="breadcrumb">
|
||||
<span class="layui-breadcrumb">
|
||||
<a href="{{ course_url }}"><i class="layui-icon layui-icon-return"></i> 返回课程</a>
|
||||
<a><cite>{{ chapter.course.title }}</cite></a>
|
||||
<a><cite>{{ chapter.title }}</cite></a>
|
||||
</span>
|
||||
|
@ -3,12 +3,14 @@
|
||||
{% block content %}
|
||||
|
||||
{% set chapter_full_url = full_url({'for':'web.chapter.show','id':chapter.id}) %}
|
||||
{% 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 qrcode_url = url({'for':'web.qrcode_img'},{'text':chapter_full_url}) %}
|
||||
|
||||
<div class="breadcrumb">
|
||||
<span class="layui-breadcrumb">
|
||||
<a href="{{ course_url }}"><i class="layui-icon layui-icon-return"></i> 返回课程</a>
|
||||
<a><cite>{{ chapter.course.title }}</cite></a>
|
||||
<a><cite>{{ chapter.title }}</cite></a>
|
||||
</span>
|
||||
|
@ -3,21 +3,24 @@
|
||||
{% block content %}
|
||||
|
||||
{% set chapter_full_url = full_url({'for':'web.chapter.show','id':chapter.id}) %}
|
||||
{% set course_url = url({'for':'web.course.show','id':chapter.course.id}) %}
|
||||
{% set learning_url = url({'for':'web.chapter.learning','id':chapter.id}) %}
|
||||
{% set danmu_url = url({'for':'web.chapter.danmu','id':chapter.id}) %}
|
||||
{% set like_url = url({'for':'web.chapter.like','id':chapter.id}) %}
|
||||
{% set qrcode_url = url({'for':'web.qrcode_img'},{'text':chapter_full_url}) %}
|
||||
{% set consult_url = url({'for':'web.consult.add'},{'chapter_id':chapter.id}) %}
|
||||
{% set liked_class = chapter.me.liked ? 'active' : '' %}
|
||||
|
||||
<div class="breadcrumb">
|
||||
<span class="layui-breadcrumb">
|
||||
<a href="{{ course_url }}"><i class="layui-icon layui-icon-return"></i> 返回课程</a>
|
||||
<a><cite>{{ chapter.course.title }}</cite></a>
|
||||
<a><cite>{{ chapter.title }}</cite></a>
|
||||
</span>
|
||||
<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"></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></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="分享到微信"><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>
|
||||
@ -111,7 +114,7 @@
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
<script src="//imgcache.qq.com/open/qcloud/video/vcplayer/TcPlayer-2.3.2.js"></script>
|
||||
<script src="//imgcache.qq.com/open/qcloud/video/vcplayer/TcPlayer-2.3.3.js"></script>
|
||||
|
||||
{{ js_include('lib/jquery.min.js') }}
|
||||
{{ js_include('lib/jquery.danmu.min.js') }}
|
||||
|
@ -5,7 +5,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">咨询内容</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="question" class="layui-textarea" placeholder="请详细描述问题,我们会尽快回复您"></textarea>
|
||||
<textarea name="question" class="layui-textarea" placeholder="请详细描述问题,我们会尽快回复您" lay-verify="required"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
|
@ -11,7 +11,7 @@
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="title">{{ item.question }}</div>
|
||||
<div class="content">{{ item.answer }}</div>
|
||||
<div class="content">{% if item.answer %} {{ item.answer }} {% else %} 稍安勿燥,请耐心等待我们的回复吧 {% endif %}</div>
|
||||
<div class="footer">
|
||||
<span class="time">{{ item.create_time|time_ago }}</span>
|
||||
<a href="javascript:" class="like" title="点赞" data-url="{{ like_url }}">
|
||||
|
@ -4,7 +4,8 @@
|
||||
|
||||
{{ partial('partials/macro_course') }}
|
||||
|
||||
{% set favorite_star_class = course.me.favorited ? 'layui-icon-star-fill' : 'layui-icon-star' %}
|
||||
{% set favorite_title = course.me.favorited ? '取消收藏' : '收藏' %}
|
||||
{% set favorite_star = course.me.favorited ? 'layui-icon-star-fill' : 'layui-icon-star' %}
|
||||
{% set full_course_url = full_url({'for':'web.course.show','id':course.id}) %}
|
||||
{% set favorite_url = url({'for':'web.course.favorite','id':course.id}) %}
|
||||
{% set qrcode_url = url({'for':'web.qrcode_img'},{'text':full_course_url}) %}
|
||||
@ -18,7 +19,7 @@
|
||||
<a><cite>{{ course.title }}</cite></a>
|
||||
</span>
|
||||
<div class="share">
|
||||
<a href="javascript:" title="收藏" data-url="{{ favorite_url }}"><i class="layui-icon {{ favorite_star_class }} icon-star"></i></a>
|
||||
<a href="javascript:" title="{{ favorite_title }}" data-url="{{ favorite_url }}"><i class="layui-icon {{ favorite_star }} icon-star"></i></a>
|
||||
<a href="javascript:" title="分享到微信" data-url="{{ qrcode_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>
|
||||
|
@ -4,32 +4,36 @@
|
||||
</div>
|
||||
<div class="info">
|
||||
{% if course.model == 'vod' %}
|
||||
<p>课程时长 <span>{{ course.attrs.duration|total_duration }}</span></p>
|
||||
<p class="item">
|
||||
<span class="key">课程时长</span><span class="value">{{ course.attrs.duration|total_duration }}</span>
|
||||
</p>
|
||||
{% elseif course.model == 'live' %}
|
||||
<p>直播时间 <span>{{ course.attrs.start_date }} ~ {{ course.attrs.end_date }}</span></p>
|
||||
{% endif %}
|
||||
{% if course.market_price > 0 %}
|
||||
<p>
|
||||
学习期限 <span class="expiry">{{ course.study_expiry }}个月</span>
|
||||
退款期限 <span class="expiry">{{ course.refund_expiry }}天</span>
|
||||
<p class="item">
|
||||
<span class="key">直播时间</span><span>{{ course.attrs.start_date }} ~ {{ course.attrs.end_date }}</span>
|
||||
</p>
|
||||
{% endif %}
|
||||
<p>
|
||||
{% if course.market_price > 0 %}
|
||||
<p class="item">
|
||||
<span class="key">学习期限</span><span class="value">{{ course.study_expiry }}个月</span>
|
||||
<span class="key">退款期限</span><span class="value">{{ course.refund_expiry }}天</span>
|
||||
</p>
|
||||
{% endif %}
|
||||
<p class="item">
|
||||
{% if course.market_price > 0 %}
|
||||
市场价格 <span class="price">{{ '¥%0.2f'|format(course.market_price) }}</span>
|
||||
<span class="key">市场价格</span><span class="price">{{ '¥%0.2f'|format(course.market_price) }}</span>
|
||||
{% else %}
|
||||
市场价格 <span class="free">免费</span>
|
||||
<span class="key">市场价格</span><span class="free">免费</span>
|
||||
{% endif %}
|
||||
{% if course.vip_price > 0 %}
|
||||
会员价格 <span class="price">{{ '¥%0.2f'|format(course.vip_price) }}</span>
|
||||
<span class="key">会员价格</span><span class="price">{{ '¥%0.2f'|format(course.vip_price) }}</span>
|
||||
{% else %}
|
||||
会员价格 <span class="free">免费</span>
|
||||
<span class="key">会员价格</span><span class="free">免费</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
<p>
|
||||
难度级别 <span>{{ level_info(course.level) }}</span>
|
||||
学习人次 <span>{{ course.user_count }}</span>
|
||||
综合评分 <span>{{ course.ratings.rating }}</span>
|
||||
<p class="item">
|
||||
<span class="key">难度级别</span><span class="value">{{ level_info(course.level) }}</span>
|
||||
<span class="key">学习人次</span><span class="value">{{ course.user_count }}</span>
|
||||
<span class="key">综合评分</span><span class="value">{{ course.ratings.rating }}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="rating">
|
||||
|
@ -22,7 +22,7 @@
|
||||
<span class="icon"><i class="layui-icon layui-icon-cellphone"></i></span>
|
||||
<span class="title">手机绑定</span>
|
||||
{% if account.phone %}
|
||||
<span class="summary">已绑定手机:{{ account.phone }}</span>
|
||||
<span class="summary">已绑定手机:{{ account.phone|anonymous }}</span>
|
||||
<span class="action"><a class="layui-btn layui-btn-sm" href="{{ act_phone_url }}">修改</a></span>
|
||||
{% else %}
|
||||
<span class="summary">可用于登录和重置密码</span>
|
||||
@ -33,7 +33,7 @@
|
||||
<span class="icon"><i class="layui-icon layui-icon-email"></i></span>
|
||||
<span class="title">邮箱绑定</span>
|
||||
{% if account.phone %}
|
||||
<span class="summary">已绑定邮箱:{{ account.email }}</span>
|
||||
<span class="summary">已绑定邮箱:{{ account.email|anonymous }}</span>
|
||||
<span class="action"><a class="layui-btn layui-btn-sm" href="{{ act_email_url }}">修改</a></span>
|
||||
{% else %}
|
||||
<span class="summary">可用于登录和重置密码</span>
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Library\Validators\Common as CommonValidator;
|
||||
use App\Services\Storage as StorageService;
|
||||
use Koogua\Ip2Region\Searcher as Ip2RegionSearcher;
|
||||
use Phalcon\Di;
|
||||
@ -207,6 +208,39 @@ function kg_ci_cover_img_url($path)
|
||||
return kg_ci_img_url($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏部分字符
|
||||
*
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
function kg_anonymous($str)
|
||||
{
|
||||
$length = mb_strlen($str);
|
||||
|
||||
if (CommonValidator::email($str)) {
|
||||
$start = 3;
|
||||
$end = mb_stripos($str, '@');
|
||||
} elseif (CommonValidator::phone($str)) {
|
||||
$start = 3;
|
||||
$end = $length - 4;
|
||||
} elseif (CommonValidator::idCard($str)) {
|
||||
$start = 3;
|
||||
$end = $length - 4;
|
||||
} else {
|
||||
$start = 1;
|
||||
$end = $length - 2;
|
||||
}
|
||||
|
||||
$list = [];
|
||||
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$list[] = ($i < $start || $i > $end) ? mb_substr($str, $i, 1) : '*';
|
||||
}
|
||||
|
||||
return join('', $list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化数字
|
||||
*
|
||||
@ -252,48 +286,12 @@ function kg_time_ago($time)
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放时长
|
||||
* 格式化时长
|
||||
*
|
||||
* @param int $time
|
||||
* @return string
|
||||
*/
|
||||
function kg_play_duration($time)
|
||||
{
|
||||
$result = '00:00';
|
||||
|
||||
if ($time > 0) {
|
||||
|
||||
$hours = floor($time / 3600);
|
||||
$minutes = floor(($time - $hours * 3600) / 60);
|
||||
$seconds = $time % 60;
|
||||
|
||||
$format = [];
|
||||
|
||||
if ($hours > 0) {
|
||||
$format[] = sprintf('%02d', $hours);
|
||||
}
|
||||
|
||||
if ($minutes >= 0) {
|
||||
$format[] = sprintf('%02d', $minutes);
|
||||
}
|
||||
|
||||
if ($seconds >= 0) {
|
||||
$format[] = sprintf('%02d', $seconds);
|
||||
}
|
||||
|
||||
$result = implode(':', $format);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 总时长
|
||||
*
|
||||
* @param int $time
|
||||
* @return string
|
||||
*/
|
||||
function kg_total_duration($time)
|
||||
function kg_duration($time)
|
||||
{
|
||||
$result = '00分钟';
|
||||
|
||||
|
@ -54,12 +54,8 @@ class Volt extends Provider
|
||||
return 'kg_can(' . $resolvedArgs . ')';
|
||||
});
|
||||
|
||||
$compiler->addFilter('play_duration', function ($resolvedArgs) {
|
||||
return 'kg_play_duration(' . $resolvedArgs . ')';
|
||||
});
|
||||
|
||||
$compiler->addFilter('total_duration', function ($resolvedArgs) {
|
||||
return 'kg_total_duration(' . $resolvedArgs . ')';
|
||||
$compiler->addFilter('duration', function ($resolvedArgs) {
|
||||
return 'kg_duration(' . $resolvedArgs . ')';
|
||||
});
|
||||
|
||||
$compiler->addFilter('human_number', function ($resolvedArgs) {
|
||||
@ -70,6 +66,10 @@ class Volt extends Provider
|
||||
return 'kg_time_ago(' . $resolvedArgs . ')';
|
||||
});
|
||||
|
||||
$compiler->addFilter('anonymous', function ($resolvedArgs) {
|
||||
return 'kg_anonymous(' . $resolvedArgs . ')';
|
||||
});
|
||||
|
||||
return $volt;
|
||||
});
|
||||
}
|
||||
|
@ -86,6 +86,20 @@ class Consult extends Repository
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $chapterId
|
||||
* @param int $userId
|
||||
* @return ConsultModel|Model|bool
|
||||
*/
|
||||
public function findUserLastChapterConsult($chapterId, $userId)
|
||||
{
|
||||
return ConsultModel::findFirst([
|
||||
'conditions' => 'chapter_id = ?1 AND user_id = ?2 AND deleted = 0',
|
||||
'bind' => [1 => $chapterId, 2 => $userId],
|
||||
'order' => 'id DESC',
|
||||
]);
|
||||
}
|
||||
|
||||
public function countConsults()
|
||||
{
|
||||
return (int)ConsultModel::count(['conditions' => 'deleted = 0']);
|
||||
|
@ -8,6 +8,7 @@ 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;
|
||||
@ -27,7 +28,8 @@ class ChapterInfo extends FrontendService
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
use CourseTrait, ChapterTrait;
|
||||
use CourseTrait;
|
||||
use ChapterTrait;
|
||||
|
||||
public function handle($id)
|
||||
{
|
||||
@ -47,10 +49,10 @@ class ChapterInfo extends FrontendService
|
||||
$this->setChapterUser($chapter, $user);
|
||||
$this->handleChapterUser($chapter, $user);
|
||||
|
||||
return $this->handleChapter($chapter);
|
||||
return $this->handleChapter($chapter, $user);
|
||||
}
|
||||
|
||||
protected function handleChapter(ChapterModel $chapter)
|
||||
protected function handleChapter(ChapterModel $chapter, UserModel $user)
|
||||
{
|
||||
$result = $this->formatChapter($chapter);
|
||||
|
||||
@ -61,18 +63,30 @@ class ChapterInfo extends FrontendService
|
||||
'position' => 0,
|
||||
'joined' => 0,
|
||||
'owned' => 0,
|
||||
'liked' => 0,
|
||||
];
|
||||
|
||||
if ($this->courseUser) {
|
||||
$me['plan_id'] = $this->courseUser->plan_id;
|
||||
}
|
||||
if ($user->id) {
|
||||
|
||||
if ($this->chapterUser) {
|
||||
$me['position'] = $this->chapterUser->position;
|
||||
}
|
||||
$likeRepo = new ChapterLikeRepo();
|
||||
|
||||
$me['joined'] = $this->joinedChapter ? 1 : 0;
|
||||
$me['owned'] = $this->ownedChapter ? 1 : 0;
|
||||
$like = $likeRepo->findChapterLike($chapter->id, $user->id);
|
||||
|
||||
if ($like && $like->deleted == 0) {
|
||||
$me['liked'] = 1;
|
||||
}
|
||||
|
||||
if ($this->courseUser) {
|
||||
$me['plan_id'] = $this->courseUser->plan_id;
|
||||
}
|
||||
|
||||
if ($this->chapterUser) {
|
||||
$me['position'] = $this->chapterUser->position;
|
||||
}
|
||||
|
||||
$me['joined'] = $this->joinedChapter ? 1 : 0;
|
||||
$me['owned'] = $this->ownedChapter ? 1 : 0;
|
||||
}
|
||||
|
||||
$result['me'] = $me;
|
||||
|
||||
@ -85,12 +99,6 @@ class ChapterInfo extends FrontendService
|
||||
'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,
|
||||
];
|
||||
}
|
||||
|
||||
@ -98,7 +106,7 @@ class ChapterInfo extends FrontendService
|
||||
{
|
||||
$item = [];
|
||||
|
||||
switch ($this->course->model) {
|
||||
switch ($chapter->model) {
|
||||
case CourseModel::MODEL_VOD:
|
||||
$item = $this->formatChapterVod($chapter);
|
||||
break;
|
||||
@ -127,7 +135,7 @@ class ChapterInfo extends FrontendService
|
||||
'play_urls' => $playUrls,
|
||||
'user_count' => $chapter->user_count,
|
||||
'like_count' => $chapter->like_count,
|
||||
'comment_count' => $chapter->comment_count,
|
||||
'consult_count' => $chapter->consult_count,
|
||||
];
|
||||
}
|
||||
|
||||
@ -166,7 +174,7 @@ class ChapterInfo extends FrontendService
|
||||
'play_urls' => $playUrls,
|
||||
'user_count' => $chapter->user_count,
|
||||
'like_count' => $chapter->like_count,
|
||||
'comment_count' => $chapter->comment_count,
|
||||
'consult_count' => $chapter->consult_count,
|
||||
];
|
||||
}
|
||||
|
||||
@ -184,7 +192,7 @@ class ChapterInfo extends FrontendService
|
||||
'content' => $read->content,
|
||||
'user_count' => $chapter->user_count,
|
||||
'like_count' => $chapter->like_count,
|
||||
'comment_count' => $chapter->comment_count,
|
||||
'consult_count' => $chapter->consult_count,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ use App\Services\Frontend\Service as FrontendService;
|
||||
use App\Services\Live as LiveService;
|
||||
use WhichBrowser\Parser as BrowserParser;
|
||||
|
||||
class ChapterBasic extends FrontendService
|
||||
class ChapterInfoBasic extends FrontendService
|
||||
{
|
||||
|
||||
use ChapterTrait;
|
@ -5,9 +5,9 @@ namespace App\Services\Frontend\Chapter;
|
||||
use App\Models\Chapter as ChapterModel;
|
||||
use App\Models\ChapterLike as ChapterLikeModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\ChapterLike as ChapterLikeRepo;
|
||||
use App\Services\Frontend\ChapterTrait;
|
||||
use App\Services\Frontend\Service as FrontendService;
|
||||
use App\Validators\Chapter as ChapterValidator;
|
||||
use App\Validators\UserDailyLimit as UserDailyLimitValidator;
|
||||
use Phalcon\Events\Manager as EventsManager;
|
||||
|
||||
@ -26,9 +26,9 @@ class ChapterLike extends FrontendService
|
||||
|
||||
$validator->checkChapterLikeLimit($user);
|
||||
|
||||
$validator = new ChapterValidator();
|
||||
$likeRepo = new ChapterLikeRepo();
|
||||
|
||||
$chapterLike = $validator->checkIfLiked($chapter->id, $user->id);
|
||||
$chapterLike = $likeRepo->findChapterLike($chapter->id, $user->id);
|
||||
|
||||
if (!$chapterLike) {
|
||||
|
||||
|
@ -15,7 +15,8 @@ use App\Validators\UserDailyLimit as UserDailyLimitValidator;
|
||||
class ConsultCreate extends FrontendService
|
||||
{
|
||||
|
||||
use CourseTrait, ChapterTrait;
|
||||
use CourseTrait;
|
||||
use ChapterTrait;
|
||||
|
||||
public function handle()
|
||||
{
|
||||
@ -35,6 +36,8 @@ class ConsultCreate extends FrontendService
|
||||
|
||||
$question = $validator->checkQuestion($post['question']);
|
||||
|
||||
$validator->checkIfDuplicated($chapter->id, $user->id, $question);
|
||||
|
||||
$priority = $this->getPriority($course, $user);
|
||||
|
||||
$consult = new ConsultModel();
|
||||
@ -44,6 +47,7 @@ class ConsultCreate extends FrontendService
|
||||
$consult->course_id = $course->id;
|
||||
$consult->chapter_id = $chapter->id;
|
||||
$consult->user_id = $user->id;
|
||||
$consult->published = 1;
|
||||
|
||||
$consult->create();
|
||||
|
||||
|
@ -11,7 +11,8 @@ use App\Validators\Consult as ConsultValidator;
|
||||
class ConsultDelete extends FrontendService
|
||||
{
|
||||
|
||||
use CourseTrait, ConsultTrait;
|
||||
use ConsultTrait;
|
||||
use CourseTrait;
|
||||
|
||||
public function handle($id)
|
||||
{
|
||||
|
@ -10,7 +10,8 @@ use App\Validators\Consult as ConsultValidator;
|
||||
class ConsultUpdate extends FrontendService
|
||||
{
|
||||
|
||||
use CourseTrait, ConsultTrait;
|
||||
use CourseTrait;
|
||||
use ConsultTrait;
|
||||
|
||||
public function handle($id)
|
||||
{
|
||||
|
@ -6,7 +6,7 @@ use App\Models\Course as CourseModel;
|
||||
use App\Services\Frontend\CourseTrait;
|
||||
use App\Services\Frontend\Service as FrontendService;
|
||||
|
||||
class CourseBasic extends FrontendService
|
||||
class CourseInfoBasic extends FrontendService
|
||||
{
|
||||
|
||||
use CourseTrait;
|
@ -5,9 +5,9 @@ namespace App\Services\Frontend\Course;
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Models\CourseFavorite as CourseFavoriteModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\CourseFavorite as CourseFavoriteRepo;
|
||||
use App\Services\Frontend\CourseTrait;
|
||||
use App\Services\Frontend\Service as FrontendService;
|
||||
use App\Validators\Course as CourseValidator;
|
||||
use App\Validators\UserDailyLimit as UserDailyLimitValidator;
|
||||
|
||||
class Favorite extends FrontendService
|
||||
@ -25,9 +25,9 @@ class Favorite extends FrontendService
|
||||
|
||||
$validator->checkFavoriteLimit($user);
|
||||
|
||||
$validator = new CourseValidator();
|
||||
$favoriteRepo = new CourseFavoriteRepo();
|
||||
|
||||
$favorite = $validator->checkIfFavorited($course->id, $user->id);
|
||||
$favorite = $favoriteRepo->findCourseFavorite($course->id, $user->id);
|
||||
|
||||
if (!$favorite) {
|
||||
|
||||
|
@ -33,8 +33,6 @@ class UserInfo extends FrontendService
|
||||
'lock_expiry_time' => $user->lock_expiry_time,
|
||||
'edu_role' => $user->edu_role,
|
||||
'admin_role' => $user->admin_role,
|
||||
'notice_count' => $user->notice_count,
|
||||
'msg_count' => $user->msg_count,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,8 @@ use App\Validators\Review as ReviewValidator;
|
||||
class ReviewDelete extends FrontendService
|
||||
{
|
||||
|
||||
use CourseTrait, ReviewTrait;
|
||||
use CourseTrait;
|
||||
use ReviewTrait;
|
||||
|
||||
public function handle($id)
|
||||
{
|
||||
|
@ -10,7 +10,8 @@ use App\Validators\Review as ReviewValidator;
|
||||
class ReviewUpdate extends FrontendService
|
||||
{
|
||||
|
||||
use CourseTrait, ReviewTrait;
|
||||
use CourseTrait;
|
||||
use ReviewTrait;
|
||||
|
||||
public function handle($id)
|
||||
{
|
||||
|
@ -8,7 +8,6 @@ use App\Exceptions\BadRequest as BadRequestException;
|
||||
use App\Models\Chapter as ChapterModel;
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Repos\Chapter as ChapterRepo;
|
||||
use App\Repos\ChapterLike as ChapterLikeRepo;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
|
||||
class Chapter extends Validator
|
||||
@ -174,19 +173,4 @@ class Chapter extends Validator
|
||||
}
|
||||
}
|
||||
|
||||
public function checkIfLiked($chapterId, $userId)
|
||||
{
|
||||
$repo = new ChapterLikeRepo();
|
||||
|
||||
$like = $repo->findChapterLike($chapterId, $userId);
|
||||
|
||||
if ($like) {
|
||||
if ($like->deleted == 0 && time() - $like->create_time > 5 * 60) {
|
||||
throw new BadRequestException('chapter.has_liked');
|
||||
}
|
||||
}
|
||||
|
||||
return $like;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ class Consult extends Validator
|
||||
|
||||
$length = kg_strlen($value);
|
||||
|
||||
if ($length < 5) {
|
||||
if ($length < 15) {
|
||||
throw new BadRequestException('consult.question_too_short');
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ class Consult extends Validator
|
||||
|
||||
$length = kg_strlen($value);
|
||||
|
||||
if ($length < 5) {
|
||||
if ($length < 15) {
|
||||
throw new BadRequestException('consult.answer_too_short');
|
||||
}
|
||||
|
||||
@ -88,6 +88,30 @@ class Consult extends Validator
|
||||
return $status;
|
||||
}
|
||||
|
||||
public function checkIfDuplicated($chapterId, $userId, $question)
|
||||
{
|
||||
$repo = new ConsultRepo();
|
||||
|
||||
$consult = $repo->findUserLastChapterConsult($chapterId, $userId);
|
||||
|
||||
if (!$consult) return;
|
||||
|
||||
$subInQuestion = kg_substr($question, 0, 20);
|
||||
$subDbQuestion = kg_substr($consult->question, 0, 20);
|
||||
|
||||
similar_text($subInQuestion, $subDbQuestion, $percent);
|
||||
|
||||
if ($percent > 80) {
|
||||
throw new BadRequestException('consult.question_duplicated');
|
||||
}
|
||||
|
||||
similar_text($question, $consult->question, $percent);
|
||||
|
||||
if ($percent > 80) {
|
||||
throw new BadRequestException('consult.question_duplicated');
|
||||
}
|
||||
}
|
||||
|
||||
public function checkIfLiked($chapterId, $userId)
|
||||
{
|
||||
$repo = new ConsultLikeRepo();
|
||||
|
@ -8,7 +8,6 @@ use App\Exceptions\BadRequest as BadRequestException;
|
||||
use App\Library\Validators\Common as CommonValidator;
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\CourseFavorite as CourseFavoriteRepo;
|
||||
|
||||
class Course extends Validator
|
||||
{
|
||||
@ -243,19 +242,4 @@ class Course extends Validator
|
||||
}
|
||||
}
|
||||
|
||||
public function checkIfFavorited($courseId, $userId)
|
||||
{
|
||||
$repo = new CourseFavoriteRepo();
|
||||
|
||||
$favorite = $repo->findCourseFavorite($courseId, $userId);
|
||||
|
||||
if ($favorite) {
|
||||
if ($favorite->deleted == 0 && time() - $favorite->create_time > 5 * 60) {
|
||||
throw new BadRequestException('course.has_favorited');
|
||||
}
|
||||
}
|
||||
|
||||
return $favorite;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -112,7 +112,6 @@ $error['course.invalid_refund_expiry'] = '无效的退款期限';
|
||||
$error['course.invalid_publish_status'] = '无效的发布状态';
|
||||
$error['course.pub_chapter_not_found'] = '尚未发现已发布的课时';
|
||||
$error['course.pub_chapter_not_enough'] = '已发布的课时太少(小于30%)';
|
||||
$error['course.has_favorited'] = '你已收藏过该课程啦';
|
||||
|
||||
/**
|
||||
* 话题相关
|
||||
@ -159,7 +158,6 @@ $error['chapter.read_not_ready'] = '文章内容尚未就绪';
|
||||
$error['chapter.live_not_start'] = '直播尚未开始';
|
||||
$error['chapter.live_time_empty'] = '直播时间尚未设置';
|
||||
$error['chapter.child_existed'] = '不允许相关操作(存在子章节)';
|
||||
$error['chapter.has_liked'] = '你已经点过赞啦';
|
||||
|
||||
/**
|
||||
* 点播相关
|
||||
@ -201,9 +199,10 @@ $error['review.has_liked'] = '你已经点过赞啦';
|
||||
$error['consult.not_found'] = '咨询不存在';
|
||||
$error['consult.invalid_private_status'] = '无效的私密状态';
|
||||
$error['consult.invalid_publish_status'] = '无效的发布状态';
|
||||
$error['consult.question_too_short'] = '问题内容太短(少于5个字符)';
|
||||
$error['consult.question_duplicated'] = '你已经咨询过类似问题啦';
|
||||
$error['consult.question_too_short'] = '问题内容太短(少于15个字符)';
|
||||
$error['consult.question_too_long'] = '问题内容太长(多于1000个字符)';
|
||||
$error['consult.answer_too_short'] = '回复内容太短(少于5个字符)';
|
||||
$error['consult.answer_too_short'] = '回复内容太短(少于15个字符)';
|
||||
$error['consult.answer_too_long'] = '回复内容太长(多于1000个字符)';
|
||||
$error['consult.has_liked'] = '你已经点过赞啦';
|
||||
|
||||
|
@ -450,6 +450,14 @@ body {
|
||||
height: 118px;
|
||||
}
|
||||
|
||||
.course-meta .info span {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.course-meta .info .value {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.course-meta .info .price {
|
||||
color: red;
|
||||
font-size: 14px;
|
||||
@ -459,13 +467,8 @@ body {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.course-meta .info span {
|
||||
color: #666;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.course-meta .rating span {
|
||||
margin: 0 3px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.course-meta .rating .layui-icon {
|
||||
@ -841,6 +844,10 @@ body {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.share .layui-icon-star-fill {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.share .active, .share .layui-icon:hover {
|
||||
color: green;
|
||||
}
|
||||
@ -870,6 +877,7 @@ body {
|
||||
left: 180px;
|
||||
bottom: 38px;
|
||||
width: 420px;
|
||||
z-index: 999;
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -5,19 +5,22 @@ layui.use(['jquery', 'helper'], function () {
|
||||
|
||||
$('.icon-praise').on('click', function () {
|
||||
var $this = $(this);
|
||||
var $parent = $this.parent();
|
||||
var $likeCount = $this.next();
|
||||
var likeCount = parseInt($likeCount.text());
|
||||
helper.checkLogin(function () {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: $this.parent().data('url'),
|
||||
url: $parent.data('url'),
|
||||
success: function () {
|
||||
if ($this.hasClass('active')) {
|
||||
$this.removeClass('active');
|
||||
$parent.attr('title', '点赞');
|
||||
$likeCount.text(likeCount - 1);
|
||||
likeCount -= 1;
|
||||
} else {
|
||||
$this.addClass('active');
|
||||
$parent.attr('title', '取消点赞');
|
||||
$likeCount.text(likeCount + 1);
|
||||
likeCount += 1;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ layui.use(['jquery', 'form', 'layer', 'helper'], function () {
|
||||
var danmuListUrl = $('input[name="chapter.danmu_url"]').val();
|
||||
var playUrls = JSON.parse($('input[name="chapter.play_urls"]').val());
|
||||
var $danmuText = $('input[name="danmu.text"]');
|
||||
var $danmuForm = $('.danmu-form');
|
||||
|
||||
var playerOptions = {
|
||||
autoplay: false,
|
||||
@ -73,13 +74,24 @@ layui.use(['jquery', 'form', 'layer', 'helper'], function () {
|
||||
*/
|
||||
$('#player').hover(function () {
|
||||
clearTimeout(dt);
|
||||
$('.danmu-form').show();
|
||||
$danmuForm.show();
|
||||
}, function () {
|
||||
dt = setTimeout(function () {
|
||||
$('.danmu-form').hide();
|
||||
$danmuForm.hide();
|
||||
}, 2500);
|
||||
});
|
||||
|
||||
/**
|
||||
* 文本框获得焦点后清理dt,不然对输入有干扰
|
||||
*/
|
||||
$danmuText.focus(function () {
|
||||
clearTimeout(dt);
|
||||
});
|
||||
|
||||
/**
|
||||
* @todo 弹幕层和播放器控制层css有抵触,待解决
|
||||
*/
|
||||
|
||||
$('#danmu').danmu({
|
||||
left: 20,
|
||||
top: 20,
|
||||
|
@ -1,8 +1,7 @@
|
||||
layui.use(['jquery', 'layer', 'helper'], function () {
|
||||
layui.use(['jquery', 'layer'], function () {
|
||||
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
var helper = layui.helper;
|
||||
|
||||
var myShare = {
|
||||
title: $('input[name="share.title"]').val(),
|
||||
@ -11,29 +10,6 @@ layui.use(['jquery', 'layer', 'helper'], function () {
|
||||
qrcode: $('input[name="share.qrcode"]').val()
|
||||
};
|
||||
|
||||
$('.icon-praise').on('click', function () {
|
||||
var $this = $(this);
|
||||
var $likeCount = $this.next();
|
||||
var likeCount = parseInt($likeCount.text());
|
||||
helper.checkLogin(function () {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: $this.parent().data('url'),
|
||||
success: function () {
|
||||
if ($this.hasClass('active')) {
|
||||
$this.removeClass('active');
|
||||
$likeCount.text(likeCount - 1);
|
||||
likeCount -= 1;
|
||||
} else {
|
||||
$this.addClass('active');
|
||||
$likeCount.text(likeCount + 1);
|
||||
likeCount += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$('.icon-wechat').on('click', function () {
|
||||
var content = '<div class="qrcode"><img src="' + myShare.qrcode + '" alt="分享到微信"></div>';
|
||||
layer.open({
|
||||
|
@ -9,17 +9,20 @@ layui.use(['jquery', 'layer', 'helper'], function () {
|
||||
*/
|
||||
$('.icon-star').on('click', function () {
|
||||
var $this = $(this);
|
||||
var $parent = $this.parent();
|
||||
helper.checkLogin(function () {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: $this.parent().data('url'),
|
||||
url: $parent.data('url'),
|
||||
success: function () {
|
||||
if ($this.hasClass('layui-icon-star-fill')) {
|
||||
$this.removeClass('layui-icon-star-fill');
|
||||
$this.addClass('layui-icon-star');
|
||||
$parent.attr('title', '收藏');
|
||||
} else {
|
||||
$this.removeClass('layui-icon-star');
|
||||
$this.addClass('layui-icon-star-fill');
|
||||
$parent.attr('title', '取消收藏');
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -74,19 +77,22 @@ layui.use(['jquery', 'layer', 'helper'], function () {
|
||||
*/
|
||||
$('body').on('click', '.icon-praise', function () {
|
||||
var $this = $(this);
|
||||
var $parent = $this.parent();
|
||||
var $likeCount = $this.next();
|
||||
var likeCount = parseInt($likeCount.text());
|
||||
helper.checkLogin(function () {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: $this.parent().data('url'),
|
||||
url: $parent.data('url'),
|
||||
success: function () {
|
||||
if ($this.hasClass('active')) {
|
||||
$this.removeClass('active');
|
||||
$parent.attr('title', '点赞');
|
||||
$likeCount.text(likeCount - 1);
|
||||
likeCount -= 1;
|
||||
} else {
|
||||
$this.addClass('active');
|
||||
$parent.attr('title', '取消点赞');
|
||||
$likeCount.text(likeCount + 1);
|
||||
likeCount += 1;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user