mirror of
https://gitee.com/koogua/course-tencent-cloud.git
synced 2025-06-22 03:32:47 +08:00
教学中心完善
This commit is contained in:
parent
8c99e5accd
commit
c9bf425fc6
@ -40,7 +40,7 @@ class CourseUserList extends Builder
|
||||
'id', 'title', 'cover',
|
||||
'market_price', 'vip_price',
|
||||
'rating', 'model', 'level', 'attrs',
|
||||
'user_count', 'lesson_count',
|
||||
'user_count', 'lesson_count', 'review_count', 'favorite_count',
|
||||
];
|
||||
|
||||
$courses = $courseRepo->findByIds($ids, $columns);
|
||||
|
@ -74,19 +74,20 @@ class TestController extends Controller
|
||||
|
||||
$pushUrl = $liveService->getPushUrl($streamName);
|
||||
|
||||
$codeUrl = $this->url->get(
|
||||
['for' => 'web.qrcode_img'],
|
||||
$qrcode = $this->url->get(
|
||||
['for' => 'web.qrcode'],
|
||||
['text' => urlencode($pushUrl)]
|
||||
);
|
||||
|
||||
$obs = [];
|
||||
|
||||
$pos = strrpos($pushUrl, '/');
|
||||
$obs['fms_url'] = substr($pushUrl, 0, $pos + 1);
|
||||
$obs['stream_code'] = substr($pushUrl, $pos + 1);
|
||||
|
||||
$obs = [
|
||||
'fms_url' => substr($pushUrl, 0, $pos + 1),
|
||||
'stream_code' => substr($pushUrl, $pos + 1),
|
||||
];
|
||||
|
||||
$this->view->pick('setting/live_push_test');
|
||||
$this->view->setVar('code_url', $codeUrl);
|
||||
$this->view->setVar('qrcode', $qrcode);
|
||||
$this->view->setVar('obs', $obs);
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ class AlipayTest extends PayTest
|
||||
|
||||
if ($code) {
|
||||
$codeUrl = $this->url->get(
|
||||
['for' => 'web.qrcode_img'],
|
||||
['for' => 'web.qrcode'],
|
||||
['text' => urlencode($code)]
|
||||
);
|
||||
}
|
||||
|
@ -79,8 +79,7 @@
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '推流测试',
|
||||
resize: false,
|
||||
area: ['680px', '380px'],
|
||||
area: ['680px', '450px'],
|
||||
content: [url, 'no']
|
||||
});
|
||||
});
|
||||
|
@ -93,8 +93,7 @@
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '推流测试',
|
||||
resize: false,
|
||||
area: ['680px', '380px'],
|
||||
area: ['680px', '450px'],
|
||||
content: [url, 'no']
|
||||
});
|
||||
});
|
||||
|
@ -1,16 +1,23 @@
|
||||
<form class="layui-form kg-form">
|
||||
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>手机推流</legend>
|
||||
</fieldset>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-inline" style="width:150px;margin-left:110px;">
|
||||
<img class="kg-qrcode" src="{{ code_url }}" alt="二维码图片">
|
||||
<div class="kg-text-center">
|
||||
<img class="kg-qrcode" src="{{ qrcode }}" alt="二维码图片">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>OBS推流</legend>
|
||||
</fieldset>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">OBS推流地址</label>
|
||||
<label class="layui-form-label">推流地址</label>
|
||||
<div class="layui-input-inline" style="width:350px;">
|
||||
<input id="tc1" class="layui-input" type="text" name="obs.fms_url" value="{{ obs.fms_url }}" readonly="true">
|
||||
<input id="tc1" class="layui-input" type="text" name="obs.fms_url" value="{{ obs.fms_url }}" readonly="readonly">
|
||||
</div>
|
||||
<div class="layui-input-inline" style="width:100px;">
|
||||
<span class="kg-copy layui-btn" data-clipboard-target="#tc1">复制</span>
|
||||
@ -18,9 +25,9 @@
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">OBS推流名称</label>
|
||||
<label class="layui-form-label">推流名称</label>
|
||||
<div class="layui-input-inline" style="width:350px;">
|
||||
<input id="tc2" class="layui-input" type="text" name="obs_stream_code" value="{{ obs.stream_code }}" readonly="true">
|
||||
<input id="tc2" class="layui-input" type="text" name="obs_stream_code" value="{{ obs.stream_code }}" readonly="readonly">
|
||||
</div>
|
||||
<div class="layui-input-inline" style="width:100px;">
|
||||
<span class="kg-copy layui-btn" data-clipboard-target="#tc2">复制</span>
|
||||
|
@ -6,9 +6,8 @@ use App\Services\Frontend\Consult\ConsultCreate as ConsultCreateService;
|
||||
use App\Services\Frontend\Consult\ConsultDelete as ConsultDeleteService;
|
||||
use App\Services\Frontend\Consult\ConsultInfo as ConsultInfoService;
|
||||
use App\Services\Frontend\Consult\ConsultLike as ConsultLikeService;
|
||||
use App\Services\Frontend\Consult\ConsultRating as ConsultRatingService;
|
||||
use App\Services\Frontend\Consult\ConsultReply as ConsultReplyService;
|
||||
use App\Services\Frontend\Consult\ConsultUpdate as ConsultUpdateService;
|
||||
use Phalcon\Mvc\View;
|
||||
|
||||
/**
|
||||
* @RoutePrefix("/consult")
|
||||
@ -21,20 +20,7 @@ class ConsultController extends Controller
|
||||
*/
|
||||
public function addAction()
|
||||
{
|
||||
$this->view->setRenderLevel(View::LEVEL_ACTION_VIEW);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/{id:[0-9]+}/edit", name="web.consult.edit")
|
||||
*/
|
||||
public function editAction($id)
|
||||
{
|
||||
$service = new ConsultInfoService();
|
||||
|
||||
$consult = $service->handle($id);
|
||||
|
||||
$this->view->setRenderLevel(View::LEVEL_ACTION_VIEW);
|
||||
$this->view->setVar('consult', $consult);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -46,10 +32,46 @@ class ConsultController extends Controller
|
||||
|
||||
$consult = $service->handle($id);
|
||||
|
||||
$this->view->setRenderLevel(View::LEVEL_ACTION_VIEW);
|
||||
$this->view->setVar('consult', $consult);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/{id:[0-9]+}/edit", name="web.consult.edit")
|
||||
*/
|
||||
public function editAction($id)
|
||||
{
|
||||
$service = new ConsultInfoService();
|
||||
|
||||
$consult = $service->handle($id);
|
||||
|
||||
$this->view->setVar('consult', $consult);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/{id:[0-9]+}/reply", name="web.consult.reply")
|
||||
*/
|
||||
public function replyAction($id)
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
|
||||
$service = new ConsultReplyService();
|
||||
|
||||
$service->handle($id);
|
||||
|
||||
$content = ['msg' => '回复咨询成功'];
|
||||
|
||||
return $this->jsonSuccess($content);
|
||||
|
||||
} else {
|
||||
|
||||
$service = new ConsultInfoService();
|
||||
|
||||
$consult = $service->handle($id);
|
||||
|
||||
$this->view->setVar('consult', $consult);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Post("/create", name="web.consult.create")
|
||||
*/
|
||||
@ -61,12 +83,9 @@ class ConsultController extends Controller
|
||||
|
||||
$service = new ConsultInfoService();
|
||||
|
||||
$consult = $service->handle($consult->id);
|
||||
$service->handle($consult->id);
|
||||
|
||||
$content = [
|
||||
'consult' => $consult,
|
||||
'msg' => '提交咨询成功',
|
||||
];
|
||||
$content = ['msg' => '提交咨询成功'];
|
||||
|
||||
return $this->jsonSuccess($content);
|
||||
}
|
||||
@ -78,12 +97,9 @@ class ConsultController extends Controller
|
||||
{
|
||||
$service = new ConsultUpdateService();
|
||||
|
||||
$consult = $service->handle($id);
|
||||
$service->handle($id);
|
||||
|
||||
$content = [
|
||||
'consult' => $consult,
|
||||
'msg' => '更新咨询成功',
|
||||
];
|
||||
$content = ['msg' => '更新咨询成功'];
|
||||
|
||||
return $this->jsonSuccess($content);
|
||||
}
|
||||
@ -118,18 +134,4 @@ class ConsultController extends Controller
|
||||
return $this->jsonSuccess($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Post("/{id:[0-9]+}/rating", name="web.consult.rating")
|
||||
*/
|
||||
public function ratingAction($id)
|
||||
{
|
||||
$service = new ConsultRatingService();
|
||||
|
||||
$service->handle($id);
|
||||
|
||||
$content = ['msg' => '评价成功'];
|
||||
|
||||
return $this->jsonSuccess($content);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,14 +30,11 @@ class MyController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/home", name="web.my.home")
|
||||
* @Get("/", name="web.my.index")
|
||||
*/
|
||||
public function homeAction()
|
||||
public function indexAction()
|
||||
{
|
||||
$this->response->redirect([
|
||||
'for' => 'web.user.show',
|
||||
'id' => $this->authUser->id,
|
||||
]);
|
||||
return $this->dispatcher->forward(['action' => 'courses']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -39,9 +39,9 @@ class PublicController extends \Phalcon\Mvc\Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/qrcode/img", name="web.qrcode_img")
|
||||
* @Get("/qrcode", name="web.qrcode")
|
||||
*/
|
||||
public function qrcodeImageAction()
|
||||
public function qrcodeAction()
|
||||
{
|
||||
$text = $this->request->getQuery('text');
|
||||
$level = $this->request->getQuery('level', 'int', 0);
|
||||
|
@ -3,8 +3,10 @@
|
||||
|
||||
namespace App\Http\Web\Controllers;
|
||||
|
||||
use App\Services\Frontend\Teaching\ConsultList as TclService;
|
||||
use App\Services\Frontend\Teaching\LiveList as TllService;
|
||||
use App\Services\Frontend\Teaching\ConsultList as ConsultListService;
|
||||
use App\Services\Frontend\Teaching\CourseList as CourseListService;
|
||||
use App\Services\Frontend\Teaching\LiveList as LiveListService;
|
||||
use App\Services\Frontend\Teaching\LivePushUrl as LivePushUrlService;
|
||||
|
||||
|
||||
/**
|
||||
@ -13,12 +15,34 @@ use App\Services\Frontend\Teaching\LiveList as TllService;
|
||||
class TeachingController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @Get("/", name="web.teaching.index")
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$this->dispatcher->forward(['action' => 'courses']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/courses", name="web.teaching.courses")
|
||||
*/
|
||||
public function coursesAction()
|
||||
{
|
||||
$service = new CourseListService();
|
||||
|
||||
$pager = $service->handle();
|
||||
|
||||
$pager->items = kg_array_object($pager->items);
|
||||
|
||||
$this->view->setVar('pager', $pager);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/lives", name="web.teaching.lives")
|
||||
*/
|
||||
public function livesAction()
|
||||
{
|
||||
$service = new TllService();
|
||||
$service = new LiveListService();
|
||||
|
||||
$pager = $service->handle();
|
||||
|
||||
@ -32,7 +56,7 @@ class TeachingController extends Controller
|
||||
*/
|
||||
public function consultsAction()
|
||||
{
|
||||
$service = new TclService();
|
||||
$service = new ConsultListService();
|
||||
|
||||
$pager = $service->handle();
|
||||
|
||||
@ -41,4 +65,30 @@ class TeachingController extends Controller
|
||||
$this->view->setVar('pager', $pager);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/live/push", name="web.teaching.live_push")
|
||||
*/
|
||||
public function livePushAction()
|
||||
{
|
||||
$service = new LivePushUrlService();
|
||||
|
||||
$pushUrl = $service->handle();
|
||||
|
||||
$qrcode = $this->url->get(
|
||||
['for' => 'web.qrcode'],
|
||||
['text' => urlencode($pushUrl)]
|
||||
);
|
||||
|
||||
$pos = strrpos($pushUrl, '/');
|
||||
|
||||
$obs = [
|
||||
'fms_url' => substr($pushUrl, 0, $pos + 1),
|
||||
'stream_code' => substr($pushUrl, $pos + 1),
|
||||
];
|
||||
|
||||
$this->view->pick('teaching/live_push');
|
||||
$this->view->setVar('qrcode', $qrcode);
|
||||
$this->view->setVar('obs', $obs);
|
||||
}
|
||||
|
||||
}
|
@ -62,7 +62,7 @@ class Trade extends Service
|
||||
|
||||
if ($text) {
|
||||
$qrCodeUrl = $this->url->get(
|
||||
['for' => 'web.qrcode_img'],
|
||||
['for' => 'web.qrcode'],
|
||||
['text' => urlencode($text)]
|
||||
);
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
{% set send_msg_url = url({'for':'web.live.send_msg','id':chapter.id}) %}
|
||||
{% set bind_user_url = url({'for':'web.live.bind_user','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 qrcode_url = url({'for':'web.qrcode'},{'text':chapter_full_url}) %}
|
||||
|
||||
<div class="breadcrumb">
|
||||
<span class="layui-breadcrumb">
|
||||
|
@ -7,7 +7,7 @@
|
||||
{% 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}) %}
|
||||
{% set qrcode_url = url({'for':'web.qrcode'},{'text':chapter_full_url}) %}
|
||||
|
||||
<div class="breadcrumb">
|
||||
<span class="layui-breadcrumb">
|
||||
|
@ -7,7 +7,7 @@
|
||||
{% 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 qrcode_url = url({'for':'web.qrcode'},{'text':chapter_full_url}) %}
|
||||
{% set consult_url = url({'for':'web.consult.add'},{'chapter_id':chapter.id}) %}
|
||||
{% set liked_class = chapter.me.liked ? 'active' : '' %}
|
||||
|
||||
|
@ -14,9 +14,9 @@
|
||||
<div class="layui-form-mid">{{ consult.chapter.title }}</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">问题</label>
|
||||
<label class="layui-form-label" for="answer">问题</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="question" class="layui-textarea" lay-verify="required">{{ consult.question }}</textarea>
|
||||
<textarea id="answer" class="layui-textarea" name="question" lay-verify="required">{{ consult.question }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
@ -30,7 +30,6 @@
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
34
app/Http/Web/Views/consult/reply.volt
Normal file
34
app/Http/Web/Views/consult/reply.volt
Normal file
@ -0,0 +1,34 @@
|
||||
{% extends 'templates/layer.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% set update_url = url({'for':'web.consult.reply','id':consult.id}) %}
|
||||
|
||||
<form class="layui-form" method="post" action="{{ update_url }}">
|
||||
<div class="layui-form-item mb0">
|
||||
<label class="layui-form-label">课程</label>
|
||||
<div class="layui-form-mid">{{ consult.course.title }}</div>
|
||||
</div>
|
||||
<div class="layui-form-item mb0">
|
||||
<label class="layui-form-label">章节</label>
|
||||
<div class="layui-form-mid">{{ consult.chapter.title }}</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">问题</label>
|
||||
<div class="layui-form-mid">{{ consult.question }}</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" for="answer">回复</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea id="answer" class="layui-textarea" name="answer" lay-verify="required">{{ consult.answer }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
@ -2,7 +2,6 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% set rating_url = url({'for':'web.consult.rating','id':consult.id}) %}
|
||||
{% set answer = consult.answer ? consult.answer : '<span class="gray">稍安勿燥,请耐心等待回复吧</span>' %}
|
||||
|
||||
<form class="layui-form review-form">
|
||||
@ -22,39 +21,6 @@
|
||||
<label class="layui-form-label">回复:</label>
|
||||
<div class="layui-form-mid">{{ answer }}</div>
|
||||
</div>
|
||||
{% if consult.answer %}
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">评分:</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="hidden" name="rating" value="{{ consult.rating }}">
|
||||
<input type="hidden" name="rating_url" value="{{ rating_url }}">
|
||||
<div id="rating"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block inline_js %}
|
||||
|
||||
<script>
|
||||
layui.use(['jquery', 'layer', 'rate'], function () {
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
var rate = layui.rate;
|
||||
var rating = $('input[name=rating]').val();
|
||||
var ratingUrl = $('input[name=rating_url]').val();
|
||||
rate.render({
|
||||
elem: '#rating',
|
||||
value: rating,
|
||||
choose: function (value) {
|
||||
$.post(ratingUrl, {rating: value}, function () {
|
||||
layer.msg('评价成功');
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
@ -1,5 +1,3 @@
|
||||
{{ partial('partials/macro_course') }}
|
||||
|
||||
{% if pager.total_pages > 0 %}
|
||||
<div class="review-list">
|
||||
{% for item in pager.items %}
|
||||
@ -13,7 +11,6 @@
|
||||
</a>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="rating">{{ star_info(item.rating) }}</div>
|
||||
<div class="title">{{ item.question }}</div>
|
||||
<div class="content">{{ item.answer }}</div>
|
||||
<div class="footer">
|
||||
|
@ -8,7 +8,7 @@
|
||||
{% 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}) %}
|
||||
{% set qrcode_url = url({'for':'web.qrcode'},{'text':full_course_url}) %}
|
||||
|
||||
<div class="breadcrumb">
|
||||
<span class="layui-breadcrumb">
|
||||
|
@ -29,6 +29,7 @@
|
||||
{% for item in pager.items %}
|
||||
{% set course_url = url({'for':'web.course.show','id':item.course.id}) %}
|
||||
{% set review_url = url({'for':'web.review.add'},{'id':item.course.id}) %}
|
||||
{% set allow_review = item.progress > 30 and item.reviewed == 0 %}
|
||||
<tr>
|
||||
<td>
|
||||
<p>标题:<a href="{{ course_url }}">{{ item.course.title }}</a> {{ model_info(item.course.model) }}</p>
|
||||
@ -39,7 +40,11 @@
|
||||
<p>进度:{{ item.progress }}%</p>
|
||||
</td>
|
||||
<td align="center">
|
||||
<button class="layui-btn layui-btn-xs btn-add-review" data-url="{{ review_url }}">评价</button>
|
||||
{% if allow_review %}
|
||||
<button class="layui-btn layui-btn-sm btn-add-review" data-url="{{ review_url }}">评价</button>
|
||||
{% else %}
|
||||
<button class="layui-btn layui-btn-sm layui-btn-disabled" title="学习进度过30%才允许评价">评价</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -14,16 +14,6 @@
|
||||
<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.refunds'}) }}">我的直播</a></li>
|
||||
<li><a href="{{ url({'for':'web.my.orders'}) }}">用户咨询</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">课程中心</div>
|
||||
<div class="layui-card-body">
|
||||
|
@ -30,8 +30,11 @@
|
||||
<li class="layui-nav-item">
|
||||
<a href="javascript:">{{ auth_user.name }}</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a href="{{ url({'for':'web.my.home'}) }}">我的主页</a></dd>
|
||||
<dd><a href="{{ url({'for':'web.my.profile'}) }}">个人设置</a></dd>
|
||||
<dd><a href="{{ url({'for':'web.user.show','id':auth_user.id}) }}">我的主页</a></dd>
|
||||
{% if auth_user.edu_role == 2 %}
|
||||
<dd><a href="{{ url({'for':'web.teaching.index'}) }}">教学中心</a></dd>
|
||||
{% endif %}
|
||||
<dd><a href="{{ url({'for':'web.my.index'}) }}">用户中心</a></dd>
|
||||
<dd><a href="{{ url({'for':'web.account.logout'}) }}">退出登录</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
|
69
app/Http/Web/Views/teaching/consults.volt
Normal file
69
app/Http/Web/Views/teaching/consults.volt
Normal file
@ -0,0 +1,69 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% set status_types = {'all':'全部','pending':'待回复','replied':'已回复'} %}
|
||||
{% set status = request.get('status','trim','all') %}
|
||||
|
||||
<div class="layout-main">
|
||||
<div class="my-sidebar">{{ partial('teaching/menu') }}</div>
|
||||
<div class="my-content">
|
||||
<div class="wrap">
|
||||
<div class="my-nav">
|
||||
<span class="title">用户咨询</span>
|
||||
{% for key,value in status_types %}
|
||||
{% set class = (status == key) ? 'layui-btn layui-btn-xs' : 'none' %}
|
||||
{% set url = url({'for':'web.teaching.consults'},{'status':key}) %}
|
||||
<a class="{{ class }}" href="{{ url }}">{{ value }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if pager.total_pages > 0 %}
|
||||
<table class="layui-table consult-table">
|
||||
<colgroup>
|
||||
<col>
|
||||
<col>
|
||||
<col width="20%">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>内容</th>
|
||||
<th>时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in pager.items %}
|
||||
{% set answer = item.answer ? item.answer : '<span class="gray">等待回复ing...</span>' %}
|
||||
{% set course_url = url({'for':'web.course.show','id':item.course.id}) %}
|
||||
{% set show_url = url({'for':'web.consult.show','id':item.id}) %}
|
||||
{% set reply_url = url({'for':'web.consult.reply','id':item.id}) %}
|
||||
{% set delete_url = url({'for':'web.consult.delete','id':item.id}) %}
|
||||
<tr>
|
||||
<td>
|
||||
<p>课程:<a href="{{ course_url }}" target="_blank">{{ item.course.title }}</a></p>
|
||||
<p class="question layui-elip" title="{{ item.question }}">提问:{{ item.question }}</p>
|
||||
<p class="answer layui-elip" title="{{ item.answer }}">回复:{{ answer }}</p>
|
||||
</td>
|
||||
<td>{{ date('Y-m-d',item.create_time) }}</td>
|
||||
<td>
|
||||
<button class="layui-btn layui-btn-xs layui-bg-green btn-show-consult" data-url="{{ show_url }}">详情</button>
|
||||
<button class="layui-btn layui-btn-xs layui-bg-blue btn-reply-consult" data-url="{{ reply_url }}">回复</button>
|
||||
<button class="layui-btn layui-btn-xs layui-bg-red kg-delete" data-url="{{ delete_url }}">删除</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{{ partial('partials/pager') }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
{{ js_include('web/js/teaching.js') }}
|
||||
|
||||
{% endblock %}
|
51
app/Http/Web/Views/teaching/courses.volt
Normal file
51
app/Http/Web/Views/teaching/courses.volt
Normal file
@ -0,0 +1,51 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{{ partial('partials/macro_course') }}
|
||||
|
||||
<div class="layout-main">
|
||||
<div class="my-sidebar">{{ partial('teaching/menu') }}</div>
|
||||
<div class="my-content">
|
||||
<div class="wrap">
|
||||
<div class="my-nav">
|
||||
<span class="title">我的课程</span>
|
||||
</div>
|
||||
{% if pager.total_pages > 0 %}
|
||||
<table class="layui-table" lay-size="lg">
|
||||
<colgroup>
|
||||
<col>
|
||||
<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 course_url = url({'for':'web.course.show','id':item.id}) %}
|
||||
<tr>
|
||||
<td><a href="{{ course_url }}">{{ item.title }}</a> {{ model_info(item.model) }}</td>
|
||||
<td><span class="layui-badge-rim">{{ item.lesson_count }}</span></td>
|
||||
<td><span class="layui-badge-rim">{{ item.user_count }}</span></td>
|
||||
<td><span class="layui-badge-rim">{{ item.favorite_count }}</span></td>
|
||||
<td><span class="layui-badge-rim">{{ item.rating }}</span></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{{ partial('partials/pager') }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
44
app/Http/Web/Views/teaching/live_push.volt
Normal file
44
app/Http/Web/Views/teaching/live_push.volt
Normal file
@ -0,0 +1,44 @@
|
||||
{% extends 'templates/layer.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form class="layui-form">
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>手机推流</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form-item">
|
||||
<div class="text-center">
|
||||
<div class="qrcode-sm"><img src="{{ qrcode }}" alt="二维码图片"></div>
|
||||
</div>
|
||||
</div>
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>OBS推流</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">推流地址</label>
|
||||
<div class="layui-input-inline" style="width:350px;">
|
||||
<input id="tc1" class="layui-input" type="text" name="obs.fms_url" value="{{ obs.fms_url }}" readonly="readonly">
|
||||
</div>
|
||||
<div class="layui-input-inline" style="width:100px;">
|
||||
<span class="kg-copy layui-btn" data-clipboard-target="#tc1">复制</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">推流名称</label>
|
||||
<div class="layui-input-inline" style="width:350px;">
|
||||
<input id="tc2" class="layui-input" type="text" name="obs_stream_code" value="{{ obs.stream_code }}" readonly="readonly">
|
||||
</div>
|
||||
<div class="layui-input-inline" style="width:100px;">
|
||||
<span class="kg-copy layui-btn" data-clipboard-target="#tc2">复制</span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
{{ js_include('lib/clipboard.min.js') }}
|
||||
{{ js_include('web/js/copy.js') }}
|
||||
|
||||
{% endblock %}
|
63
app/Http/Web/Views/teaching/lives.volt
Normal file
63
app/Http/Web/Views/teaching/lives.volt
Normal file
@ -0,0 +1,63 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{{ partial('partials/macro_course') }}
|
||||
|
||||
<div class="layout-main">
|
||||
<div class="my-sidebar">{{ partial('teaching/menu') }}</div>
|
||||
<div class="my-content">
|
||||
<div class="wrap">
|
||||
<div class="my-nav">
|
||||
<span class="title">课程直播</span>
|
||||
</div>
|
||||
{% if pager.total_pages > 0 %}
|
||||
<table class="layui-table">
|
||||
<colgroup>
|
||||
<col>
|
||||
<col>
|
||||
<col width="12%">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>课程/章节</th>
|
||||
<th>直播时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in pager.items %}
|
||||
{% set course_url = url({'for':'web.course.show','id':item.course.id}) %}
|
||||
{% set chapter_url = url({'for':'web.chapter.show','id':item.chapter.id}) %}
|
||||
{% set live_push_url = url({'for':'web.teaching.live_push','id':item.chapter.id}) %}
|
||||
{% set allow_push = (item.start_time - 1800 < time()) and (time() < item.start_time + 1800) %}
|
||||
<tr>
|
||||
<td>
|
||||
<p>课程:<a href="{{ course_url }}" target="_blank">{{ item.course.title }}</a></p>
|
||||
<p>章节:<a href="{{ chapter_url }}" target="_blank">{{ item.chapter.title }}</a></p>
|
||||
</td>
|
||||
<td>{{ date('m-d',item.start_time) }} {{ date('H:i',item.start_time) }} ~ {{ date('H:i',item.end_time) }}</td>
|
||||
<td align="center">
|
||||
{% if allow_push %}
|
||||
<button class="layui-btn layui-btn-sm btn-live-push" data-url="{{ live_push_url }}">推流</button>
|
||||
{% else %}
|
||||
<button class="layui-btn layui-btn-sm layui-btn-disabled" title="开播前后半小时之内才允许推流">推流</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{{ partial('partials/pager') }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
{{ js_include('web/js/teaching.js') }}
|
||||
|
||||
{% endblock %}
|
10
app/Http/Web/Views/teaching/menu.volt
Normal file
10
app/Http/Web/Views/teaching/menu.volt
Normal file
@ -0,0 +1,10 @@
|
||||
<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.teaching.courses'}) }}">我的课程</a></li>
|
||||
<li><a href="{{ url({'for':'web.teaching.lives'}) }}">我的直播</a></li>
|
||||
<li><a href="{{ url({'for':'web.teaching.consults'}) }}">课程咨询</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
@ -5,6 +5,7 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrfToken.getToken() }}">
|
||||
<title>{{ site_seo.getTitle() }}</title>
|
||||
{{ icon_link('favicon.ico') }}
|
||||
{{ css_link('lib/layui/css/layui.css') }}
|
||||
{{ css_link('web/css/common.css') }}
|
||||
|
@ -56,13 +56,6 @@ class Consult extends Model
|
||||
*/
|
||||
public $answer;
|
||||
|
||||
/**
|
||||
* 评分
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $rating;
|
||||
|
||||
/**
|
||||
* 赞成数
|
||||
*
|
||||
@ -103,7 +96,7 @@ class Consult extends Model
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $answer_time;
|
||||
public $reply_time;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
@ -145,10 +138,6 @@ class Consult extends Model
|
||||
{
|
||||
$this->update_time = time();
|
||||
|
||||
if (!empty($this->answer) && $this->answer_time == 0) {
|
||||
$this->answer_time = time();
|
||||
}
|
||||
|
||||
if ($this->deleted == 1) {
|
||||
$this->published = 0;
|
||||
}
|
||||
|
@ -348,7 +348,7 @@ class Course extends Repository
|
||||
|
||||
$result = [];
|
||||
|
||||
if ($rows->count() == 0) {
|
||||
if ($rows->count() > 0) {
|
||||
$result = kg_array_column($rows->toArray(), 'course_id');
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,8 @@ use WhichBrowser\Parser as BrowserParser;
|
||||
trait ChapterBasicInfoTrait
|
||||
{
|
||||
|
||||
use ChapterLiveTrait;
|
||||
|
||||
protected function handleBasicInfo(ChapterModel $chapter)
|
||||
{
|
||||
$result = [];
|
||||
@ -65,7 +67,7 @@ trait ChapterBasicInfoTrait
|
||||
|
||||
$liveService = new LiveService();
|
||||
|
||||
$stream = "chapter-{$chapter->id}";
|
||||
$stream = $this->getLiveStreamName($chapter->id);
|
||||
|
||||
$format = $browserParser->isType('desktop') ? 'flv' : 'hls';
|
||||
|
||||
|
@ -115,7 +115,7 @@ class ChapterInfo extends FrontendService
|
||||
|
||||
$this->incrCourseUserCount($course);
|
||||
|
||||
$this->incrUserCourseCount($course);
|
||||
$this->incrUserCourseCount($user);
|
||||
}
|
||||
|
||||
protected function handleChapterUser(ChapterModel $chapter, UserModel $user)
|
||||
@ -162,9 +162,4 @@ class ChapterInfo extends FrontendService
|
||||
$chapter->update();
|
||||
}
|
||||
|
||||
protected function getLiveStreamName($id)
|
||||
{
|
||||
return "chapter_{$id}";
|
||||
}
|
||||
|
||||
}
|
||||
|
13
app/Services/Frontend/Chapter/ChapterLiveTrait.php
Normal file
13
app/Services/Frontend/Chapter/ChapterLiveTrait.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Frontend\Chapter;
|
||||
|
||||
trait ChapterLiveTrait
|
||||
{
|
||||
|
||||
protected function getLiveStreamName($id)
|
||||
{
|
||||
return "chapter_{$id}";
|
||||
}
|
||||
|
||||
}
|
@ -6,7 +6,7 @@ use App\Services\Frontend\ConsultTrait;
|
||||
use App\Services\Frontend\Service as FrontendService;
|
||||
use App\Validators\Consult as ConsultValidator;
|
||||
|
||||
class ConsultRating extends FrontendService
|
||||
class ConsultReply extends FrontendService
|
||||
{
|
||||
|
||||
use ConsultTrait;
|
||||
@ -21,14 +21,10 @@ class ConsultRating extends FrontendService
|
||||
|
||||
$validator = new ConsultValidator();
|
||||
|
||||
$validator->checkOwner($user->id, $consult->user_id);
|
||||
|
||||
$validator->checkIfAllowRate($consult);
|
||||
|
||||
$rating = $validator->checkRating($post['rating']);
|
||||
|
||||
$consult->rating = $rating;
|
||||
$validator->checkTeacher($consult, $user);
|
||||
|
||||
$consult->answer = $validator->checkAnswer($post['answer']);
|
||||
$consult->reply_time = time();
|
||||
$consult->update();
|
||||
|
||||
return $consult;
|
@ -23,13 +23,19 @@ class ConsultUpdate extends FrontendService
|
||||
|
||||
$validator->checkOwner($user->id, $consult->owner_id);
|
||||
|
||||
$validator->checkIfAllowEdit($consult);
|
||||
$validator->checkConsultEdit($consult);
|
||||
|
||||
$question = $validator->checkQuestion($post['question']);
|
||||
$data = [];
|
||||
|
||||
$consult->question = $question;
|
||||
if (isset($post['question'])) {
|
||||
$data['question'] = $validator->checkQuestion($post['question']);
|
||||
}
|
||||
|
||||
$consult->update();
|
||||
if (isset($post['private'])) {
|
||||
$data['private'] = $validator->checkPrivateStatus($post['private']);
|
||||
}
|
||||
|
||||
$consult->update($data);
|
||||
|
||||
return $consult;
|
||||
}
|
||||
|
@ -58,8 +58,8 @@ class ConsultList extends FrontendService
|
||||
'id' => $consult['id'],
|
||||
'question' => $consult['question'],
|
||||
'answer' => $consult['answer'],
|
||||
'rating' => $consult['rating'],
|
||||
'like_count' => $consult['like_count'],
|
||||
'reply_time' => $consult['reply_time'],
|
||||
'create_time' => $consult['create_time'],
|
||||
'update_time' => $consult['update_time'],
|
||||
'owner' => $owner,
|
||||
|
@ -74,6 +74,8 @@ class CourseList extends FrontendService
|
||||
'level' => $course['level'],
|
||||
'user_count' => $course['user_count'],
|
||||
'lesson_count' => $course['lesson_count'],
|
||||
'review_count' => $course['review_count'],
|
||||
'favorite_count' => $course['favorite_count'],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ class ConsultList extends FrontendService
|
||||
|
||||
$params = $pagerQuery->getParams();
|
||||
|
||||
$params['user_id'] = $user->id;
|
||||
$params['owner_id'] = $user->id;
|
||||
$params['published'] = 1;
|
||||
|
||||
$sort = $pagerQuery->getSort();
|
||||
@ -56,8 +56,8 @@ class ConsultList extends FrontendService
|
||||
'id' => $consult['id'],
|
||||
'question' => $consult['question'],
|
||||
'answer' => $consult['answer'],
|
||||
'rating' => $consult['rating'],
|
||||
'like_count' => $consult['like_count'],
|
||||
'reply_time' => $consult['reply_time'],
|
||||
'create_time' => $consult['create_time'],
|
||||
'update_time' => $consult['update_time'],
|
||||
'course' => $course,
|
||||
|
@ -53,6 +53,8 @@ class CourseList extends FrontendService
|
||||
'level' => $course['level'],
|
||||
'user_count' => (int)$course['user_count'],
|
||||
'lesson_count' => (int)$course['lesson_count'],
|
||||
'review_count' => (int)$course['review_count'],
|
||||
'favorite_count' => (int)$course['favorite_count'],
|
||||
'teacher' => json_decode($course['teacher']),
|
||||
'category' => json_decode($course['category']),
|
||||
];
|
||||
|
@ -21,6 +21,7 @@ class ConsultList extends FrontendService
|
||||
|
||||
$pagerQuery = new PagerQuery();
|
||||
|
||||
$params = $pagerQuery->getParams();
|
||||
$page = $pagerQuery->getPage();
|
||||
$limit = $pagerQuery->getLimit();
|
||||
|
||||
@ -30,9 +31,17 @@ class ConsultList extends FrontendService
|
||||
return [];
|
||||
}
|
||||
|
||||
$courseIds = kg_array_column($courses->toArray(), 'id');
|
||||
$params['status'] = $params['status'] ?? null;
|
||||
|
||||
$pager = $this->paginate($courseIds, $page, $limit);
|
||||
if ($params['status'] == 'pending') {
|
||||
$params['replied'] = 0;
|
||||
} elseif ($params['status'] == 'replied') {
|
||||
$params['replied'] = 1;
|
||||
}
|
||||
|
||||
$params['course_id'] = kg_array_column($courses->toArray(), 'id');
|
||||
|
||||
$pager = $this->paginate($params, $page, $limit);
|
||||
|
||||
return $this->handleConsults($pager);
|
||||
}
|
||||
@ -63,8 +72,8 @@ class ConsultList extends FrontendService
|
||||
'id' => $consult['id'],
|
||||
'question' => $consult['question'],
|
||||
'answer' => $consult['answer'],
|
||||
'rating' => $consult['rating'],
|
||||
'like_count' => $consult['like_count'],
|
||||
'reply_time' => $consult['reply_time'],
|
||||
'create_time' => $consult['create_time'],
|
||||
'update_time' => $consult['update_time'],
|
||||
'course' => $course,
|
||||
@ -78,13 +87,27 @@ class ConsultList extends FrontendService
|
||||
return $pager;
|
||||
}
|
||||
|
||||
protected function paginate($courseIds, $page = 1, $limit = 15)
|
||||
protected function paginate($where, $page = 1, $limit = 15)
|
||||
{
|
||||
$builder = $this->modelsManager->createBuilder()
|
||||
->from(ConsultModel::class)
|
||||
->inWhere('course_id', $courseIds)
|
||||
->andWhere('published = 1')
|
||||
->orderBy('priority ASC');
|
||||
$builder = $this->modelsManager->createBuilder();
|
||||
|
||||
$builder->from(ConsultModel::class);
|
||||
|
||||
$builder->where('published = 1');
|
||||
|
||||
if (!empty($where['course_id'])) {
|
||||
$builder->inWhere('course_id', $where['course_id']);
|
||||
}
|
||||
|
||||
if (isset($where['replied'])) {
|
||||
if ($where['replied'] == 1) {
|
||||
$builder->andWhere('reply_time > 0');
|
||||
} else {
|
||||
$builder->andWhere('reply_time = 0');
|
||||
}
|
||||
}
|
||||
|
||||
$builder->orderBy('id DESC');
|
||||
|
||||
$pager = new PagerQueryBuilder([
|
||||
'builder' => $builder,
|
||||
|
84
app/Services/Frontend/Teaching/CourseList.php
Normal file
84
app/Services/Frontend/Teaching/CourseList.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Frontend\Teaching;
|
||||
|
||||
use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder;
|
||||
use App\Library\Paginator\Query as PagerQuery;
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Models\CourseUser as CourseUserModel;
|
||||
use App\Services\Frontend\Service as FrontendService;
|
||||
|
||||
class CourseList extends FrontendService
|
||||
{
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$user = $this->getLoginUser();
|
||||
|
||||
$pagerQuery = new PagerQuery();
|
||||
|
||||
$page = $pagerQuery->getPage();
|
||||
$limit = $pagerQuery->getLimit();
|
||||
|
||||
$pager = $this->paginate($user->id, $page, $limit);
|
||||
|
||||
return $this->handleCourses($pager);
|
||||
}
|
||||
|
||||
protected function handleCourses($pager)
|
||||
{
|
||||
if ($pager->total_items == 0) {
|
||||
return $pager;
|
||||
}
|
||||
|
||||
$items = [];
|
||||
|
||||
$baseUrl = kg_ci_base_url();
|
||||
|
||||
foreach ($pager->items->toArray() as $course) {
|
||||
|
||||
$course['cover'] = $baseUrl . $course['cover'];
|
||||
|
||||
$items[] = [
|
||||
'id' => $course['id'],
|
||||
'title' => $course['title'],
|
||||
'cover' => $course['cover'],
|
||||
'market_price' => (float)$course['market_price'],
|
||||
'vip_price' => (float)$course['vip_price'],
|
||||
'rating' => (float)$course['rating'],
|
||||
'model' => $course['model'],
|
||||
'level' => $course['level'],
|
||||
'user_count' => $course['user_count'],
|
||||
'lesson_count' => $course['lesson_count'],
|
||||
'review_count' => $course['review_count'],
|
||||
'favorite_count' => $course['favorite_count'],
|
||||
];
|
||||
}
|
||||
|
||||
$pager->items = $items;
|
||||
|
||||
return $pager;
|
||||
}
|
||||
|
||||
protected function paginate($userId, $page = 1, $limit = 15)
|
||||
{
|
||||
$builder = $this->modelsManager->createBuilder();
|
||||
|
||||
$builder->columns('c.*');
|
||||
$builder->addFrom(CourseModel::class, 'c');
|
||||
$builder->join(CourseUserModel::class, 'c.id = cu.course_id', 'cu');
|
||||
$builder->where('cu.user_id = :user_id:', ['user_id' => $userId]);
|
||||
$builder->andWhere('cu.role_type = :role_type:', ['role_type' => CourseUserModel::ROLE_TEACHER]);
|
||||
$builder->andWhere('c.published = 1');
|
||||
$builder->orderBy('c.id DESC');
|
||||
|
||||
$pager = new PagerQueryBuilder([
|
||||
'builder' => $builder,
|
||||
'page' => $page,
|
||||
'limit' => $limit,
|
||||
]);
|
||||
|
||||
return $pager->paginate();
|
||||
}
|
||||
|
||||
}
|
@ -68,12 +68,15 @@ class LiveList extends FrontendService
|
||||
|
||||
protected function paginate($courseIds, $page = 1, $limit = 15)
|
||||
{
|
||||
$startTime = strtotime('today');
|
||||
|
||||
$builder = $this->modelsManager->createBuilder()
|
||||
->columns(['c.id', 'c.title', 'c.course_id', 'cl.start_time', 'cl.end_time'])
|
||||
->addFrom(ChapterModel::class, 'c')
|
||||
->join(ChapterLiveModel::class, 'c.id = cl.chapter_id', 'cl')
|
||||
->inWhere('cl.course_id', $courseIds)
|
||||
->orderBy('cl.start_time DESC');
|
||||
->andWhere('cl.start_time > :start_time:', ['start_time' => $startTime])
|
||||
->orderBy('cl.start_time ASC');
|
||||
|
||||
$pager = new PagerQueryBuilder([
|
||||
'builder' => $builder,
|
||||
|
29
app/Services/Frontend/Teaching/LivePushUrl.php
Normal file
29
app/Services/Frontend/Teaching/LivePushUrl.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Frontend\Teaching;
|
||||
|
||||
use App\Services\Frontend\Chapter\ChapterLiveTrait;
|
||||
use App\Services\Frontend\ChapterTrait;
|
||||
use App\Services\Frontend\Service as FrontendService;
|
||||
use App\Services\Live as LiveService;
|
||||
|
||||
class LivePushUrl extends FrontendService
|
||||
{
|
||||
|
||||
use ChapterTrait;
|
||||
use ChapterLiveTrait;
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$chapterId = $this->request->getQuery('chapter_id');
|
||||
|
||||
$chapter = $this->checkChapter($chapterId);
|
||||
|
||||
$service = new LiveService();
|
||||
|
||||
$steamName = $this->getLiveStreamName($chapter->id);
|
||||
|
||||
return $service->getPushUrl($steamName);
|
||||
}
|
||||
|
||||
}
|
@ -73,6 +73,7 @@ class Live extends Service
|
||||
} catch (TencentCloudSDKException $e) {
|
||||
|
||||
$this->logger->error('Describe Live Stream State Exception ' . kg_json_encode([
|
||||
'line' => $e->getLine(),
|
||||
'code' => $e->getErrorCode(),
|
||||
'message' => $e->getMessage(),
|
||||
'requestId' => $e->getRequestId(),
|
||||
@ -118,6 +119,7 @@ class Live extends Service
|
||||
} catch (TencentCloudSDKException $e) {
|
||||
|
||||
$this->logger->error('Forbid Live Stream Exception ' . kg_json_encode([
|
||||
'line' => $e->getLine(),
|
||||
'code' => $e->getErrorCode(),
|
||||
'message' => $e->getMessage(),
|
||||
'requestId' => $e->getRequestId(),
|
||||
@ -161,6 +163,7 @@ class Live extends Service
|
||||
} catch (TencentCloudSDKException $e) {
|
||||
|
||||
$this->logger->error('Resume Live Stream Exception ' . kg_json_encode([
|
||||
'line' => $e->getLine(),
|
||||
'code' => $e->getErrorCode(),
|
||||
'message' => $e->getMessage(),
|
||||
'requestId' => $e->getRequestId(),
|
||||
|
@ -3,9 +3,13 @@
|
||||
namespace App\Validators;
|
||||
|
||||
use App\Exceptions\BadRequest as BadRequestException;
|
||||
use App\Exceptions\Forbidden as ForbiddenException;
|
||||
use App\Models\Consult as ConsultModel;
|
||||
use App\Models\CourseUser as CourseUserModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\Consult as ConsultRepo;
|
||||
use App\Repos\ConsultLike as ConsultLikeRepo;
|
||||
use App\Repos\CourseUser as CourseUserRepo;
|
||||
|
||||
class Consult extends Validator
|
||||
{
|
||||
@ -71,15 +75,6 @@ class Consult extends Validator
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function checkRating($rating)
|
||||
{
|
||||
if (!in_array($rating, [1, 2, 3, 4, 5])) {
|
||||
throw new BadRequestException('consult.invalid_rating');
|
||||
}
|
||||
|
||||
return $rating;
|
||||
}
|
||||
|
||||
public function checkPrivateStatus($status)
|
||||
{
|
||||
if (!in_array($status, [0, 1])) {
|
||||
@ -98,13 +93,26 @@ class Consult extends Validator
|
||||
return $status;
|
||||
}
|
||||
|
||||
public function checkIfAllowEdit(ConsultModel $consult)
|
||||
public function checkTeacher(ConsultModel $consult, UserModel $user)
|
||||
{
|
||||
$repo = new CourseUserRepo();
|
||||
|
||||
$record = $repo->findCourseUser($consult->course_id, $user->id);
|
||||
|
||||
$privOk = $record && $record->role_type == CourseUserModel::ROLE_TEACHER;
|
||||
|
||||
if (!$privOk) {
|
||||
throw new ForbiddenException('sys.forbidden');
|
||||
}
|
||||
}
|
||||
|
||||
public function checkConsultEdit(ConsultModel $consult)
|
||||
{
|
||||
/**
|
||||
* (1)已回复不允许修改提问
|
||||
* (2)发表三天以后不能修改提问
|
||||
*/
|
||||
$case1 = !empty($consult->answer);
|
||||
$case1 = $consult->reply_time > 0;
|
||||
$case2 = time() - $consult->create_time > 3 * 86400;
|
||||
|
||||
if ($case1 || $case2) {
|
||||
@ -112,26 +120,6 @@ class Consult extends Validator
|
||||
}
|
||||
}
|
||||
|
||||
public function checkIfAllowRate(ConsultModel $consult)
|
||||
{
|
||||
/**
|
||||
* 未回复不允许评价
|
||||
*/
|
||||
if (empty($consult->answer)) {
|
||||
throw new BadRequestException('consult.rate_not_allowed');
|
||||
}
|
||||
|
||||
/**
|
||||
* 已评价,三天后不能更改评价
|
||||
*/
|
||||
$case1 = $consult->rating > 0;
|
||||
$case2 = time() - $consult->answer_time > 3 * 86400;
|
||||
|
||||
if ($case1 && $case2) {
|
||||
throw new BadRequestException('consult.rate_not_allowed');
|
||||
}
|
||||
}
|
||||
|
||||
public function checkIfDuplicated($question, $chapterId, $userId)
|
||||
{
|
||||
$repo = new ConsultRepo();
|
||||
|
@ -210,7 +210,6 @@ $error['consult.question_too_long'] = '问题内容太长(多于1000个字符
|
||||
$error['consult.answer_too_short'] = '回复内容太短(少于15个字符)';
|
||||
$error['consult.answer_too_long'] = '回复内容太长(多于1000个字符)';
|
||||
$error['consult.edit_not_allowed'] = '当前不允许修改操作';
|
||||
$error['consult.rate_not_allowed'] = '当前不允许评价';
|
||||
$error['consult.has_liked'] = '你已经点过赞啦';
|
||||
|
||||
/**
|
||||
|
@ -159,8 +159,8 @@ img.kg-avatar {
|
||||
}
|
||||
|
||||
img.kg-qrcode {
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 3px dashed #ccc;
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,12 @@
|
||||
border: 3px dashed #ccc;
|
||||
}
|
||||
|
||||
.qrcode-sm img {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 3px dashed #ccc;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
|
10
public/static/web/js/copy.js
Normal file
10
public/static/web/js/copy.js
Normal file
@ -0,0 +1,10 @@
|
||||
layui.use(['layer'], function () {
|
||||
|
||||
var layer = layui.layer;
|
||||
var clipboard = new ClipboardJS('.kg-copy');
|
||||
|
||||
clipboard.on('success', function (e) {
|
||||
layer.msg('内容已经复制到剪贴板');
|
||||
});
|
||||
|
||||
});
|
48
public/static/web/js/teaching.js
Normal file
48
public/static/web/js/teaching.js
Normal file
@ -0,0 +1,48 @@
|
||||
layui.use(['jquery', 'layer'], function () {
|
||||
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
|
||||
/**
|
||||
* 查看咨询
|
||||
*/
|
||||
$('.btn-show-consult').on('click', function () {
|
||||
var url = $(this).data('url');
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '咨询详情',
|
||||
content: url,
|
||||
area: ['720px', '480px']
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 回复咨询
|
||||
*/
|
||||
$('.btn-reply-consult').on('click', function () {
|
||||
var url = $(this).data('url');
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '回复咨询',
|
||||
content: [url, 'no'],
|
||||
area: ['720px', '400px'],
|
||||
cancel: function () {
|
||||
parent.location.reload();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 直播推流
|
||||
*/
|
||||
$('.btn-live-push').on('click', function () {
|
||||
var url = $(this).data('url');
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '直播推流',
|
||||
content: [url, 'no'],
|
||||
area: ['640px', '420px']
|
||||
});
|
||||
});
|
||||
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user