初始化项目:添加后端代码、ThinkPHP框架、前端资源
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
<?php
|
||||
|
||||
namespace app\api\controller\course;
|
||||
|
||||
use app\common\controller\Api;
|
||||
use mysql_xdevapi\Collection;
|
||||
|
||||
/**
|
||||
* 课程
|
||||
*/
|
||||
class Column extends Api
|
||||
{
|
||||
// 无需登录的接口,*表示全部
|
||||
protected $noNeedLogin = ['*'];
|
||||
protected $noNeedRight = '*';
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
$this->columnDirModel = new \app\admin\model\course\ColumnDir;
|
||||
$this->model = new \app\admin\model\course\ColumnBind;
|
||||
$this->courseModel = new \app\admin\model\course\Course;
|
||||
}
|
||||
/**
|
||||
* 获取专栏目录
|
||||
* @return void
|
||||
*/
|
||||
public function getDir(){
|
||||
|
||||
$courseId = input("id");
|
||||
$row = $this->columnDirModel->courseIdGetList($courseId);
|
||||
return $this->success("获取成功",$row);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取专栏所属课程
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCourse(){
|
||||
$courseId = input('id');
|
||||
$sort = input('sort','asc');
|
||||
|
||||
$courseInfo = $this->courseModel->get($courseId);
|
||||
|
||||
if(!$courseInfo){
|
||||
return $this->error("获取课程信息错误");
|
||||
}
|
||||
|
||||
$list = $this->model
|
||||
->with(['course'])
|
||||
->where([
|
||||
'column_bind.column_id'=>$courseId,
|
||||
'course.status'=>1
|
||||
])
|
||||
->order("column_bind.sort {$sort}, column_bind.createtime {$courseInfo['column_update']}")
|
||||
->select();
|
||||
|
||||
//判断有没有订阅
|
||||
$isSubscription = \app\common\model\user\Subscription::getSubscriptionAuth($this->auth->id,$courseId);
|
||||
|
||||
if(!empty($list)){
|
||||
foreach ($list as $index => $item){
|
||||
$item['course'] = $item['course']->toArray();
|
||||
$item->getRelation('course')->visible(['name','cover','id','updatetime','views','type','type_text','pay_type']);
|
||||
$item['course'] = $this->courseModel->structrue($item['course'],'decode');
|
||||
$item->visible(['id','course','try','subscription']);
|
||||
$isCourseSubscription = \app\common\model\user\Subscription::getSubscriptionAuth($this->auth->id,$item['course']['id']);
|
||||
|
||||
if($isSubscription || $isCourseSubscription || $item->try){
|
||||
$list[$index]['subscription'] = 1;
|
||||
}else{
|
||||
$list[$index]['subscription'] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success("获取成功",$list);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取专栏目录 新
|
||||
* @return void
|
||||
*/
|
||||
public function getColumnDir(){
|
||||
$courseId = input('id');
|
||||
$sort = input('sort','asc');
|
||||
|
||||
$courseInfo = $this->courseModel->get($courseId);
|
||||
|
||||
if(!$courseInfo){
|
||||
return $this->error("获取课程信息错误");
|
||||
}
|
||||
|
||||
$list = $this->model
|
||||
->with(['bindcourse'])
|
||||
->where([
|
||||
'column_bind.column_id'=>$courseId,
|
||||
])
|
||||
->order("column_bind.sort {$sort}, column_bind.createtime {$courseInfo['column_update']}")
|
||||
->select();
|
||||
|
||||
|
||||
//判断有没有订阅
|
||||
$isSubscription = \app\common\model\user\Subscription::getSubscriptionAuth($this->auth->id,$courseId);
|
||||
|
||||
if(!empty($list)){
|
||||
foreach ($list as $index => &$item){
|
||||
$item->visible(['id','bindcourse','try','subscription','type','p_id','title']);
|
||||
$item->getRelation('bindcourse')->visible(['name','cover','id','updatetime','views','type','type_text','status','pay_type','no']);
|
||||
$item = $item->toArray();
|
||||
if($item['type'] == 1){
|
||||
if(!$item['bindcourse']['id'] || $item['bindcourse']['status']!=1){
|
||||
unset($list[$index]);
|
||||
continue;
|
||||
}
|
||||
$item['bindcourse'] = $this->courseModel->structrue($item['bindcourse'],'decode');
|
||||
$isCourseSubscription = \app\common\model\user\Subscription::getSubscriptionAuth($this->auth->id,$item['bindcourse']['id']);
|
||||
if($isSubscription || $isCourseSubscription || $item['try']){
|
||||
$list[$index]['subscription'] = 1;
|
||||
}else{
|
||||
$list[$index]['subscription'] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
//重新给数组排序
|
||||
$list = array_values($list);
|
||||
}
|
||||
|
||||
return $this->success("获取成功",$list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下一课程
|
||||
* @return mixed
|
||||
*/
|
||||
public function getNextCourse() {
|
||||
$courseId = input('course_id');
|
||||
$columnId = input('column_id');
|
||||
|
||||
// 1. 验证专栏和课程是否存在
|
||||
$columnInfo = $this->courseModel->get($columnId);
|
||||
if (!$columnInfo) {
|
||||
return $this->success();
|
||||
}
|
||||
|
||||
$courseInfo = $this->model->where(['column_id' => $columnId, 'course_id' => $courseId])->find();
|
||||
if (!$courseInfo) {
|
||||
return $this->success();
|
||||
}
|
||||
|
||||
// 2. 关键修正:查询专栏下所有课程和目录(包含type=1和type=2)
|
||||
$allItems = $this->model
|
||||
->with(['course'])
|
||||
->where([
|
||||
'course.status'=>1
|
||||
])
|
||||
->where('column_id', $columnId)
|
||||
->field('column_bind.id, column_bind.course_id, column_bind.type, column_bind.sort, column_bind.p_id, column_bind.createtime')
|
||||
->select();
|
||||
|
||||
if (empty($allItems)) {
|
||||
return $this->success();
|
||||
}
|
||||
|
||||
// 3. 构建映射和子元素分组(方便快速查找父元素和子课程)
|
||||
$itemMap = []; // 按 id 映射所有元素(id是column_bind表的主键)
|
||||
$childrenGroups = []; // 按 p_id 分组(p_id对应父目录的id)
|
||||
$courseIdToItemId = []; // 课程id -> column_bind.id 的映射(用于快速定位当前课程)
|
||||
foreach ($allItems as $item) {
|
||||
$itemMap[$item['id']] = $item;
|
||||
$pId = $item['p_id'];
|
||||
if (!isset($childrenGroups[$pId])) {
|
||||
$childrenGroups[$pId] = [];
|
||||
}
|
||||
$childrenGroups[$pId][] = $item;
|
||||
// 关联课程id和column_bind的id(因为传入的是course_id,不是column_bind的id)
|
||||
if ($item['type'] == 1) { // 只有课程有course_id
|
||||
$courseIdToItemId[$item['course_id']] = $item['id'];
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 筛选一级元素(p_id=0的课程/目录)并排序
|
||||
$level1Items = $childrenGroups[0] ?? [];
|
||||
usort($level1Items, function($a, $b) {
|
||||
// 排序规则:sort升序 -> createtime升序
|
||||
if ($a['sort'] != $b['sort']) {
|
||||
return $a['sort'] - $b['sort'];
|
||||
}
|
||||
return strcmp($a['createtime'], $b['createtime']);
|
||||
});
|
||||
|
||||
// 5. 构建最终排序列表(一级元素 + 对应二级课程)
|
||||
$finalSortedList = [];
|
||||
foreach ($level1Items as $item) {
|
||||
$finalSortedList[] = $item;
|
||||
// 如果是目录,且有子课程,将子课程排序后追加
|
||||
if ($item['type'] == 2 && isset($childrenGroups[$item['id']])) {
|
||||
$children = $childrenGroups[$item['id']];
|
||||
// 子课程排序规则:sort升序 -> createtime升序
|
||||
usort($children, function($a, $b) {
|
||||
if ($a['sort'] != $b['sort']) {
|
||||
return $a['sort'] - $b['sort'];
|
||||
}
|
||||
return strcmp($a['createtime'], $b['createtime']);
|
||||
});
|
||||
$finalSortedList = array_merge($finalSortedList, $children);
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 找到当前课程在排序列表中的位置
|
||||
$currentItemId = $courseIdToItemId[$courseId] ?? null;
|
||||
$currentIndex = -1;
|
||||
foreach ($finalSortedList as $index => $item) {
|
||||
if ($item['id'] == $currentItemId) {
|
||||
$currentIndex = $index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 7. 查找下一个课程(跳过目录,只找type=1的)
|
||||
$nextCourse = null;
|
||||
$listCount = count($finalSortedList);
|
||||
for ($i = $currentIndex + 1; $i < $listCount; $i++) {
|
||||
$candidate = $finalSortedList[$i];
|
||||
if ($candidate['type'] == 1) { // 只取课程
|
||||
$nextCourse = $candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$nextCourse) {
|
||||
return $this->success('');
|
||||
}
|
||||
|
||||
// 8. 关联课程详情并返回
|
||||
$nextCourseInfo = $this->courseModel->get($nextCourse['course_id']);
|
||||
if (!$nextCourseInfo) {
|
||||
return $this->success();
|
||||
}
|
||||
|
||||
// 整理返回字段
|
||||
$result = $nextCourseInfo->visible(['name', 'column_id', 'cover', 'id', 'updatetime', 'views', 'type', 'type_text', 'status', 'pay_type', 'no'])->toArray();
|
||||
$result['column_id'] = $columnId;
|
||||
|
||||
return $this->success("获取成功", $result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace app\api\controller\course;
|
||||
|
||||
use app\common\controller\Api;
|
||||
|
||||
/**
|
||||
* 评论
|
||||
*/
|
||||
class Comment extends Api
|
||||
{
|
||||
// 无需登录的接口,*表示全部
|
||||
protected $noNeedLogin = ['index'];
|
||||
protected $noNeedRight = '*';
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
$this->model = new \app\common\model\course\Comment;
|
||||
$this->commentLikeModel = new \app\common\model\course\CommentLike;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取评论列表
|
||||
* @return void
|
||||
*/
|
||||
public function index(){
|
||||
$courseId = $this->request->post('course_id');
|
||||
|
||||
$limit = input('limit',10);
|
||||
$page = input('page',1);
|
||||
|
||||
$sort = input('sort','time');
|
||||
|
||||
$list = $this->model->getList($courseId,[
|
||||
'limit'=>$limit,
|
||||
'page'=>$page,
|
||||
'sort'=>$sort,
|
||||
'user_id'=>$this->auth->id
|
||||
]);
|
||||
|
||||
|
||||
$this->success('获取成功', $list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加评论
|
||||
* @return void
|
||||
*/
|
||||
public function add(){
|
||||
$content = $this->request->post('content');
|
||||
$courseId = $this->request->post('course_id');
|
||||
$replyCommentId = $this->request->post('reply_comment_id');
|
||||
|
||||
$discussConfig = \app\common\model\config\System::getConfig('discuss');
|
||||
|
||||
if($discussConfig['comment_status'] == 'close'){
|
||||
$this->error("评论功能暂时关闭");
|
||||
}
|
||||
|
||||
if(mb_strlen($content) > 1000){
|
||||
$this->error("评论内容长度超出限制");
|
||||
}
|
||||
|
||||
if(empty($content)){
|
||||
$this->error("请完善评论内容");
|
||||
}
|
||||
|
||||
$data = [
|
||||
'createtime'=>time(),
|
||||
'content'=>$content,
|
||||
'course_id'=>$courseId,
|
||||
'uniacid'=>UNIACID,
|
||||
'user_id'=>$this->auth->id
|
||||
];
|
||||
if($replyCommentId){
|
||||
$replyCommentData = $this->model->getComment($replyCommentId);
|
||||
if(!$replyCommentData){
|
||||
$this->error("回复的评论不存在");
|
||||
}
|
||||
$data['reply_comment_id'] = $replyCommentData['id'];
|
||||
$data['reply_user_id'] = $replyCommentData['user_id'];
|
||||
}
|
||||
|
||||
|
||||
$successTip = '评论成功';
|
||||
|
||||
if($discussConfig['comment_audit'] == 'open'){
|
||||
$data['status'] = 0;
|
||||
$successTip = '提交成功,评论将在审核通过后显示';
|
||||
}
|
||||
|
||||
$this->model->save($data);
|
||||
|
||||
$this->success($successTip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除评价
|
||||
* @return void
|
||||
*/
|
||||
public function del(){
|
||||
$commentId = $this->request->post('comment_id');
|
||||
$commentData = $this->model->getComment($commentId);
|
||||
|
||||
if(!$commentData || $commentData['user_id'] != $this->auth->id){
|
||||
$this->error("删除错误,请重试");
|
||||
}
|
||||
|
||||
$this->model->del($commentData['id']);
|
||||
|
||||
$this->success("删除成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 喜欢评价
|
||||
* @return void
|
||||
*/
|
||||
public function like(){
|
||||
$commentId = $this->request->post('comment_id');
|
||||
|
||||
$commentData = $this->model->getComment($commentId);
|
||||
|
||||
if(!$commentData){
|
||||
$this->error("获取评论数据失败,请刷新重试");
|
||||
}
|
||||
|
||||
$this->commentLikeModel->setLike($commentId,$this->auth->id);
|
||||
|
||||
$this->success("操作成功");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
<?php
|
||||
|
||||
namespace app\api\controller\course;
|
||||
|
||||
use app\common\controller\Api;
|
||||
use app\common\model\user\Study as StudyModel;
|
||||
use think\Cache;
|
||||
/**
|
||||
* 课程
|
||||
*/
|
||||
class Course extends Api
|
||||
{
|
||||
// 无需登录的接口,*表示全部
|
||||
protected $noNeedLogin = ['*'];
|
||||
protected $noNeedRight = '*';
|
||||
protected $SubscriptionModel;
|
||||
protected $groupBindModel;
|
||||
protected $model;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
header("Access-Control-Allow-Origin:*");
|
||||
parent::_initialize();
|
||||
|
||||
$this->model = new \app\admin\model\course\Course;
|
||||
$this->styleModel = new StudyModel();
|
||||
$this->commentModel = new \app\common\model\course\Comment();
|
||||
$this->groupBindModel = new \app\api\model\course\GroupBind();
|
||||
$this->columnBindModel = new \app\api\model\course\ColumnBind();
|
||||
$this->SubscriptionModel = new \app\common\model\user\Subscription();
|
||||
}
|
||||
/**
|
||||
* 获取课程分组列表
|
||||
* @return void
|
||||
*/
|
||||
public function getList(){
|
||||
|
||||
$limit = input('limit',10);
|
||||
$page = input('page',1);
|
||||
$groupId = input('group');
|
||||
$isDeep = input('is_deep', 1);
|
||||
|
||||
$searchKey = input('searchKey','');
|
||||
$sort = input('sort','time');
|
||||
$type = input('type','');
|
||||
|
||||
if ($groupId) {
|
||||
$groupModel = new \app\admin\model\course\Group();
|
||||
$groupIds = [];
|
||||
|
||||
if ($isDeep) {
|
||||
$groupIds = $this->getRelatedGroupIds($groupModel, $groupId);
|
||||
} else {
|
||||
$groupIds = [$groupId];
|
||||
}
|
||||
|
||||
$list = $this->groupBindModel->getCourseListByGroupIds($groupIds, [
|
||||
'limit'=>$limit,
|
||||
'page'=>$page,
|
||||
'searchKey'=>$searchKey,
|
||||
'sort'=>$sort,
|
||||
'type'=>$type,
|
||||
]);
|
||||
} else {
|
||||
$list = $this->groupBindModel->getCourseList(0, [
|
||||
'limit'=>$limit,
|
||||
'page'=>$page,
|
||||
'searchKey'=>$searchKey,
|
||||
'sort'=>$sort,
|
||||
'type'=>$type,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->success('获取成功', $list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分组及其所有相关分组ID(包括上级和下级)
|
||||
* @param object $groupModel
|
||||
* @param int $groupId
|
||||
* @return array
|
||||
*/
|
||||
protected function getRelatedGroupIds($groupModel, $groupId)
|
||||
{
|
||||
$groupIds = [$groupId];
|
||||
|
||||
$this->getParentGroupIds($groupModel, $groupId, $groupIds);
|
||||
|
||||
$this->getChildGroupIdsRecursive($groupModel, $groupId, $groupIds);
|
||||
|
||||
return array_unique($groupIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归获取上级分组ID
|
||||
* @param object $groupModel
|
||||
* @param int $groupId
|
||||
* @param array $groupIds
|
||||
*/
|
||||
protected function getParentGroupIds($groupModel, $groupId, &$groupIds)
|
||||
{
|
||||
$group = $groupModel
|
||||
->where('id', $groupId)
|
||||
->where('status', 1)
|
||||
->where('uniacid', UNIACID)
|
||||
->find();
|
||||
|
||||
if ($group && $group['parent_id'] > 0) {
|
||||
$parent = $groupModel
|
||||
->where('id', $group['parent_id'])
|
||||
->where('status', 1)
|
||||
->where('uniacid', UNIACID)
|
||||
->find();
|
||||
|
||||
if ($parent) {
|
||||
$groupIds[] = $parent['id'];
|
||||
$this->getParentGroupIds($groupModel, $parent['id'], $groupIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归获取下级分组ID
|
||||
* @param object $groupModel
|
||||
* @param int $parentId
|
||||
* @param array $groupIds
|
||||
*/
|
||||
protected function getChildGroupIdsRecursive($groupModel, $parentId, &$groupIds)
|
||||
{
|
||||
$children = $groupModel
|
||||
->where('parent_id', $parentId)
|
||||
->where('status', 1)
|
||||
->where('uniacid', UNIACID)
|
||||
->column('id');
|
||||
|
||||
foreach ($children as $childId) {
|
||||
$groupIds[] = $childId;
|
||||
$this->getChildGroupIdsRecursive($groupModel, $childId, $groupIds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取课程详情
|
||||
* @return void
|
||||
*/
|
||||
public function detail(){
|
||||
$id = input('id',0);
|
||||
$addViews = input('add_views',0);//是否增加流量,因为直播需要频繁刷新
|
||||
|
||||
|
||||
$row = $this->model->get($id);
|
||||
|
||||
if (!$row) {
|
||||
$this->error(__('No Results were found'));
|
||||
}
|
||||
$row = $row->toArray();
|
||||
$row = $this->model->structrue($row, 'decode');
|
||||
|
||||
|
||||
//增加浏览量
|
||||
if($addViews){
|
||||
$this->model->where(['id'=>$id])->setInc('views');
|
||||
}
|
||||
|
||||
$buyData = \app\common\model\course\Course::getPrice($row['id']);
|
||||
|
||||
$row = array_merge($row,$buyData);
|
||||
|
||||
$row['subscription'] = \app\common\model\user\Subscription::getSubscriptionAuth($this->auth->id,$row['id']);
|
||||
//是否拥有付费会员卡免费权益(用于前端显示【加入学习】按钮)
|
||||
$row['vip_free_access'] = \app\common\model\user\Subscription::getVipFreeAccess($this->auth->id,$row['id']);
|
||||
|
||||
if($row['type'] == 'live'){
|
||||
$row['try_read_content'] = $row['detail'];
|
||||
$row['try_read_status'] = 1;
|
||||
$row['live_start_time'] = strtotime($row['live_start_time']);
|
||||
$row['live_end_time'] = strtotime($row['live_end_time']);
|
||||
|
||||
//获取直播地址
|
||||
$row['live_room'] = (new \app\common\model\live\Room)->courseGetRoom($row['id']);
|
||||
|
||||
if($row['live_type'] == 2){
|
||||
//要计算当前播放进度
|
||||
$row['live_current_time'] = time() - $row['live_start_time'];
|
||||
}
|
||||
|
||||
if($row['subscription']){
|
||||
//判断有没有成为直播课程成员
|
||||
$userInfo = (new \app\admin\model\live\User)->joinLive($this->auth->id,$row['id']);
|
||||
|
||||
if($userInfo['black']){
|
||||
return $this->error("你已被管理员拉黑,无法观看直播");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
$row = $this->courseDataLimit($row);
|
||||
|
||||
$row['is_virtual_pay'] = \app\common\library\pay\VirtualPayService::isUseVirtualPay($row['type']);
|
||||
if ($row['is_virtual_pay']) {
|
||||
$row = \app\common\library\pay\VirtualPayService::convertPriceFields($row, ['price', 'price_marking']);
|
||||
}
|
||||
|
||||
return $this->success("获取成功", $row);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 课程数据限制
|
||||
* 根据是否已订阅返回相关数据
|
||||
* @param $courseInfo
|
||||
* @return void
|
||||
*/
|
||||
public function courseDataLimit($courseInfo){
|
||||
|
||||
$showField = ['sales_type','type','live_type','live_screen_ratio','live_current_time','live_room','limit_copy','bullet_screen','pay_type','warm_up_cover','type_text','views','video_path','video_patch','name','briefing','live_start_time','live_end_time','price','price_marking','createtime','cover','bind_data','audio_path','detail','id','try_listen_content','try_read_status','try_watch_status','try_watch_content','try_read_content','try_listen_status','subscription','vip_free_access'];
|
||||
|
||||
foreach ($courseInfo as $key => &$item){
|
||||
if(!in_array($key,$showField)){
|
||||
unset($courseInfo[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if(!$courseInfo['subscription']){
|
||||
$courseInfo['detail'] = '';
|
||||
$courseInfo['audio_path'] = [];
|
||||
$courseInfo['video_path'] = [];
|
||||
|
||||
$bindDataFiled = ['id','filename','filesize','filetype','auth'];
|
||||
foreach ($courseInfo['bind_data'] as &$item){
|
||||
if(!isset($item['auth'])){
|
||||
$item['auth'] = 'previewdown';
|
||||
}
|
||||
foreach ($item as $key => $value){
|
||||
if(!in_array($key,$bindDataFiled)){
|
||||
unset($item[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$courseInfo['study_num'] = $this->styleModel->getCourseStudyNum($courseInfo['id']);
|
||||
$courseInfo['comment_num'] = $this->commentModel->getCourseCommentCount($courseInfo['id']);
|
||||
|
||||
$courseInfo['try_listen_status'] = !empty($courseInfo['try_listen_status']) ? true:false;
|
||||
$courseInfo['try_read_status'] = !empty($courseInfo['try_read_status']) ? true:false;
|
||||
$courseInfo['try_watch_status'] = !empty($courseInfo['try_watch_status']) ? true:false;
|
||||
//跑马灯
|
||||
$courseInfo['bullet_screen'] = $courseInfo['bullet_screen'] == 1 ? $this->auth->username : 0;
|
||||
|
||||
$vodFileType = ['audio_path','video_path','try_listen_content','try_watch_content'];
|
||||
foreach ($vodFileType as $vodFile){
|
||||
if(isset($courseInfo[$vodFile]) && $courseInfo[$vodFile] && $courseInfo[$vodFile]['storage'] == 'alivod'){
|
||||
$courseInfo[$vodFile]['fullurl'] = \addons\alivod\library\Alivod::parseAliovdTag($courseInfo[$vodFile]['fullurl']);
|
||||
}
|
||||
}
|
||||
|
||||
$courseInfo['detail'] = \addons\alivod\library\Alivod::parseContentAliovdTag($courseInfo['detail']);
|
||||
|
||||
$courseInfo['try_read_content'] = \addons\alivod\library\Alivod::parseContentAliovdTag($courseInfo['try_read_content']);
|
||||
|
||||
if($courseInfo['bind_data']){
|
||||
foreach ($courseInfo['bind_data'] as &$item){
|
||||
if(isset($item['fullurl'])){
|
||||
try{
|
||||
$parseVodTag = \addons\alivod\library\Alivod::getMezzanineInfo($item['fullurl']);
|
||||
if($parseVodTag && isset($parseVodTag->Mezzanine) && isset($parseVodTag->Mezzanine->FileURL)){
|
||||
$item['fullurl'] = $parseVodTag->Mezzanine->FileURL;
|
||||
}
|
||||
}catch (\Exception $e){}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $courseInfo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取课程所属专栏
|
||||
* @return void
|
||||
*/
|
||||
public function getBelongsColumn($course_id)
|
||||
{
|
||||
|
||||
$cacheData = Cache::get(\app\common\constant\cache\Keys::COURSE_BELONGS_COLUMN.$course_id);
|
||||
|
||||
if($cacheData){
|
||||
return $this->success("获取成功", $cacheData);
|
||||
}
|
||||
|
||||
$list = $this->columnBindModel
|
||||
->with(['column'])
|
||||
->where([
|
||||
'course_id'=>$course_id,
|
||||
'column.status'=>1,
|
||||
'column_bind.type'=>1,
|
||||
'column_bind.status'=>1
|
||||
])
|
||||
->select();
|
||||
|
||||
if($list){
|
||||
foreach ($list as &$item){
|
||||
$item->count = $this->columnBindModel->where([
|
||||
'column_id'=>$item['column_id']
|
||||
])->count();
|
||||
$item->getRelation('column')->visible(['name','cover','id']);
|
||||
$item->visible(['id','column','count']);
|
||||
}
|
||||
|
||||
$list = collection($list)->toArray();
|
||||
}
|
||||
|
||||
Cache::tag(\app\common\constant\cache\Keys::COURSE_TAG)->set(\app\common\constant\cache\Keys::COURSE_BELONGS_COLUMN.$course_id,$list);
|
||||
|
||||
|
||||
return $this->success("获取成功", $list);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
<?php
|
||||
|
||||
namespace app\api\controller\course;
|
||||
|
||||
use app\common\controller\Api;
|
||||
use app\admin\model\course\Group as GroupModel;
|
||||
use app\api\model\course\Group as ApiGroupModel;
|
||||
|
||||
/**
|
||||
* 课程分组接口
|
||||
*/
|
||||
class Group extends Api
|
||||
{
|
||||
protected $noNeedLogin = ['*'];
|
||||
protected $noNeedRight = ['*'];
|
||||
|
||||
protected $model = null;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
$this->model = new GroupModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分组列表(支持指定层级)
|
||||
*
|
||||
* @param int $id 指定分组ID,不传则获取所有一级分组
|
||||
* @return void
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$id = $this->request->param('id', 0);
|
||||
|
||||
// 获取课程配置
|
||||
$courseConfig = \app\common\model\config\System::getConfig('course');
|
||||
$groupLevel = isset($courseConfig['group_level']) ? intval($courseConfig['group_level']) : 4;
|
||||
|
||||
// 获取一级分组
|
||||
$query = $this->model
|
||||
->where('parent_id', 0)
|
||||
->where('status', 1)
|
||||
->where('uniacid', UNIACID)
|
||||
->order('sort', 'asc')
|
||||
->order('id', 'asc');
|
||||
|
||||
if ($id) {
|
||||
$query = $query->where('id', $id);
|
||||
}
|
||||
|
||||
$list = $query->select();
|
||||
|
||||
if (empty($list)) {
|
||||
$this->error(__('No Results were found'));
|
||||
}
|
||||
|
||||
// 获取完整的分类树
|
||||
$result = [];
|
||||
foreach ($list as $item) {
|
||||
$result[] = $this->getGroupTree($item, $groupLevel);
|
||||
}
|
||||
|
||||
$this->success('获取成功', [
|
||||
'list' => $result,
|
||||
'group_level' => $groupLevel
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有分组树
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
// 获取课程配置
|
||||
$courseConfig = \app\common\model\config\System::getConfig('course');
|
||||
$groupLevel = isset($courseConfig['group_level']) ? intval($courseConfig['group_level']) : 4;
|
||||
|
||||
$list = $this->model
|
||||
->where('parent_id', 0)
|
||||
->where('status', 1)
|
||||
->where('uniacid', UNIACID)
|
||||
->order('sort', 'asc')
|
||||
->order('id', 'asc')
|
||||
->select();
|
||||
|
||||
$result = [];
|
||||
foreach ($list as $item) {
|
||||
$result[] = $this->getGroupTree($item, $groupLevel);
|
||||
}
|
||||
|
||||
$this->success('获取成功', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定层级分组
|
||||
*/
|
||||
public function level()
|
||||
{
|
||||
$level = $this->request->param('level', 1);
|
||||
$parentId = $this->request->param('parent_id', 0);
|
||||
|
||||
// 获取课程配置
|
||||
$courseConfig = \app\common\model\config\System::getConfig('course');
|
||||
$groupLevel = isset($courseConfig['group_level']) ? intval($courseConfig['group_level']) : 4;
|
||||
|
||||
if ($level > $groupLevel) {
|
||||
$this->error('超出最大层级限制,最大支持' . $groupLevel . '级');
|
||||
}
|
||||
|
||||
$list = $this->model
|
||||
->where('parent_id', $parentId)
|
||||
->where('status', 1)
|
||||
->where('uniacid', UNIACID)
|
||||
->order('sort', 'asc')
|
||||
->order('id', 'asc')
|
||||
->select();
|
||||
|
||||
$result = [];
|
||||
foreach ($list as $item) {
|
||||
$data = [
|
||||
'id' => $item['id'],
|
||||
'name' => $item['name'],
|
||||
'parent_id' => $item['parent_id'],
|
||||
'image' => $item['image'] ?? '',
|
||||
'sort' => $item['sort'] ?? 0,
|
||||
];
|
||||
$result[] = $data;
|
||||
}
|
||||
|
||||
$this->success('获取成功', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归获取分组树
|
||||
*/
|
||||
protected function getGroupTree($group, $maxLevel = 4, $currentLevel = 1)
|
||||
{
|
||||
$data = [
|
||||
'id' => $group['id'],
|
||||
'name' => $group['name'],
|
||||
'parent_id' => $group['parent_id'],
|
||||
'image' => $group['image'] ?? '',
|
||||
'sort' => $group['sort'] ?? 0,
|
||||
];
|
||||
|
||||
$data['is_virtual_pay'] = $this->checkGroupHasVirtualPay($group['id']);
|
||||
|
||||
// 如果未达到最大层级,继续获取子分组
|
||||
if ($currentLevel < $maxLevel) {
|
||||
$children = $this->model
|
||||
->where('parent_id', $group['id'])
|
||||
->where('status', 1)
|
||||
->where('uniacid', UNIACID)
|
||||
->order('sort', 'asc')
|
||||
->order('id', 'asc')
|
||||
->select();
|
||||
|
||||
if (!empty($children)) {
|
||||
$data['children'] = [];
|
||||
foreach ($children as $child) {
|
||||
$data['children'][] = $this->getGroupTree($child, $maxLevel, $currentLevel + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查分组下是否有虚拟支付课程
|
||||
* @param int $groupId 分组ID
|
||||
* @return int 1-有虚拟支付课程 0-无
|
||||
*/
|
||||
protected function checkGroupHasVirtualPay($groupId)
|
||||
{
|
||||
$virtualPayConfig = \app\common\model\config\System::getConfig('virtual_pay');
|
||||
if (!$virtualPayConfig || ($virtualPayConfig['status'] ?? 'close') !== 'open') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$virtualGoodsTypes = $virtualPayConfig['virtual_goods_types'] ?? [];
|
||||
if (empty($virtualGoodsTypes) || !is_array($virtualGoodsTypes)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$prefix = \think\Config::get('database.prefix');
|
||||
$courseTypes = \think\Db::name('course_bind_group')
|
||||
->alias('gb')
|
||||
->join($prefix . 'course c', 'gb.course_id = c.id')
|
||||
->where('gb.group_id', $groupId)
|
||||
->where('c.status', 1)
|
||||
->where('c.uniacid', UNIACID)
|
||||
->column('c.type');
|
||||
|
||||
foreach ($courseTypes as $type) {
|
||||
if (in_array($type, $virtualGoodsTypes, true)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分组详情
|
||||
*/
|
||||
public function detail()
|
||||
{
|
||||
$id = $this->request->param('id', 0);
|
||||
|
||||
if (!$id) {
|
||||
$this->error('分组ID不能为空');
|
||||
}
|
||||
|
||||
$group = $this->model
|
||||
->where('id', $id)
|
||||
->where('status', 1)
|
||||
->where('uniacid', UNIACID)
|
||||
->find();
|
||||
|
||||
if (!$group) {
|
||||
$this->error(__('No Results were found'));
|
||||
}
|
||||
|
||||
$data = [
|
||||
'id' => $group['id'],
|
||||
'name' => $group['name'],
|
||||
'parent_id' => $group['parent_id'],
|
||||
'image' => $group['image'] ?? '',
|
||||
'sort' => $group['sort'] ?? 0,
|
||||
];
|
||||
|
||||
// 获取父级信息
|
||||
if ($group['parent_id'] > 0) {
|
||||
$parent = $this->model
|
||||
->where('id', $group['parent_id'])
|
||||
->where('uniacid', UNIACID)
|
||||
->find();
|
||||
$data['parent_name'] = $parent ? $parent['name'] : '';
|
||||
} else {
|
||||
$data['parent_name'] = '';
|
||||
}
|
||||
|
||||
$this->success('获取成功', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取课程分组列表(兼容旧接口)
|
||||
* @return void
|
||||
*/
|
||||
public function getList(){
|
||||
$groupId = $this->request->param('group', 0);
|
||||
$isDeep = $this->request->param('is_deep', 1);
|
||||
$parentId = $this->request->param('parent_id', 0);
|
||||
|
||||
if ($parentId) {
|
||||
$list = $this->model
|
||||
->where('parent_id', $parentId)
|
||||
->where('status', 1)
|
||||
->where('uniacid', UNIACID)
|
||||
->order('sort', 'asc')
|
||||
->order('id', 'asc')
|
||||
->select();
|
||||
|
||||
$this->success('返回成功', $list);
|
||||
return;
|
||||
}
|
||||
|
||||
$groupIds = [];
|
||||
if ($groupId) {
|
||||
if ($isDeep) {
|
||||
$groupIds = $this->getRelatedGroupIds($groupId);
|
||||
} else {
|
||||
$groupIds = [$groupId];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($groupIds)) {
|
||||
$groupBindModel = new \app\api\model\course\GroupBind();
|
||||
$list = $groupBindModel->getCourseListByGroupIds($groupIds);
|
||||
} else {
|
||||
$apiModel = new ApiGroupModel();
|
||||
$list = $apiModel->getList();
|
||||
}
|
||||
|
||||
$this->success('返回成功', $list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分组及其所有相关分组ID(包括上级和下级)
|
||||
* @param int $groupId
|
||||
* @return array
|
||||
*/
|
||||
protected function getRelatedGroupIds($groupId)
|
||||
{
|
||||
$groupIds = [$groupId];
|
||||
|
||||
$this->getParentGroupIds($groupId, $groupIds);
|
||||
|
||||
$this->getChildGroupIdsRecursive($groupId, $groupIds);
|
||||
|
||||
return array_unique($groupIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归获取上级分组ID
|
||||
* @param int $groupId
|
||||
* @param array $groupIds
|
||||
*/
|
||||
protected function getParentGroupIds($groupId, &$groupIds)
|
||||
{
|
||||
$group = $this->model
|
||||
->where('id', $groupId)
|
||||
->where('status', 1)
|
||||
->where('uniacid', UNIACID)
|
||||
->find();
|
||||
|
||||
if ($group && $group['parent_id'] > 0) {
|
||||
$parent = $this->model
|
||||
->where('id', $group['parent_id'])
|
||||
->where('status', 1)
|
||||
->where('uniacid', UNIACID)
|
||||
->find();
|
||||
|
||||
if ($parent) {
|
||||
$groupIds[] = $parent['id'];
|
||||
$this->getParentGroupIds($parent['id'], $groupIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归获取下级分组ID
|
||||
* @param int $parentId
|
||||
* @param array $groupIds
|
||||
*/
|
||||
protected function getChildGroupIdsRecursive($parentId, &$groupIds)
|
||||
{
|
||||
$children = $this->model
|
||||
->where('parent_id', $parentId)
|
||||
->where('status', 1)
|
||||
->where('uniacid', UNIACID)
|
||||
->column('id');
|
||||
|
||||
foreach ($children as $childId) {
|
||||
$groupIds[] = $childId;
|
||||
$this->getChildGroupIdsRecursive($childId, $groupIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace app\api\controller\course;
|
||||
|
||||
use app\common\controller\Api;
|
||||
use app\admin\model\course\Course as CourseModel;
|
||||
use app\common\model\user\Subscription as SubscriptionModel;
|
||||
/**
|
||||
* 订阅课程
|
||||
*/
|
||||
class Subscription extends Api
|
||||
{
|
||||
// 无需登录的接口,*表示全部
|
||||
protected $noNeedLogin = [];
|
||||
protected $noNeedRight = '*';
|
||||
protected $courseModel;
|
||||
protected $SubscriptionModel;
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
$this->courseModel = new CourseModel();
|
||||
$this->SubscriptionModel = new SubscriptionModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* 密码兑换
|
||||
* @return void
|
||||
*/
|
||||
public function passwordPay(){
|
||||
$password = $this->request->post('password','');
|
||||
$courseId = $this->request->post('course_id','');
|
||||
|
||||
$userId = $this->auth->id;
|
||||
|
||||
if(empty($password) || empty($courseId)){
|
||||
$this->error('请完善参数后再提交');
|
||||
}
|
||||
|
||||
//获取课程详情
|
||||
$courseInfo = $this->courseModel->where([
|
||||
'id'=>$courseId,
|
||||
'status'=>1,
|
||||
'pay_type'=>'password'
|
||||
])->find();
|
||||
if (!$courseInfo) {
|
||||
$this->error(__('未找到相关课程信息'));
|
||||
}
|
||||
$courseInfo = $courseInfo->toArray();
|
||||
|
||||
\app\common\model\course\Course::checkSalesType($courseInfo);
|
||||
|
||||
if($courseInfo['password'] != $password){
|
||||
$this->error(__('兑换密码错误'));
|
||||
}
|
||||
|
||||
//判断是否订阅过了
|
||||
$userCourse = $this->SubscriptionModel->getUserCourse($userId,$courseId);
|
||||
if($userCourse){
|
||||
$this->error(__('该课程已经订阅过了'));
|
||||
}
|
||||
|
||||
//添加订阅记录
|
||||
$result = $this->SubscriptionModel->setUserCourse($userId,$courseId);
|
||||
|
||||
if(!$result){
|
||||
$this->error(__('订阅失败'));
|
||||
}
|
||||
|
||||
$this->success('订阅成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 免费加入学习
|
||||
* 适用以下任一情形:
|
||||
* 1. 课程本身免费(pay_type=free 或 pay_type=pay 且价格为 0)→ get_type=free
|
||||
* 2. 用户付费会员卡免费权益命中该课程 → get_type=vip
|
||||
* 仅支持 article/video/audio/live/column 类型课程
|
||||
* @return void
|
||||
*/
|
||||
public function free(){
|
||||
$courseId = $this->request->post('course_id','');
|
||||
|
||||
$userId = $this->auth->id;
|
||||
|
||||
if(empty($courseId)){
|
||||
$this->error('请完善参数后再提交');
|
||||
}
|
||||
|
||||
//获取课程详情
|
||||
$courseInfo = $this->courseModel->where([
|
||||
'id'=>$courseId,
|
||||
'status'=>1
|
||||
])->find();
|
||||
|
||||
|
||||
if (!$courseInfo) {
|
||||
$this->error(__('未找到相关课程信息'));
|
||||
}
|
||||
|
||||
//仅支持指定类型的课程加入学习
|
||||
$allowTypes = ['article','video','audio','live','column'];
|
||||
if (!in_array($courseInfo['type'], $allowTypes)) {
|
||||
$this->error(__('当前课程类型不支持加入学习'));
|
||||
}
|
||||
|
||||
//加入学习的资格判定:课程免费 或 用户付费会员卡免费权益命中
|
||||
$isFreeCourse = \app\common\model\user\Subscription::isFreeCourse($courseId);
|
||||
$hasVipFreeAccess = false;
|
||||
if (!$isFreeCourse) {
|
||||
$hasVipFreeAccess = \app\common\model\user\Subscription::getVipFreeAccess($userId, $courseId);
|
||||
}
|
||||
|
||||
if (!$isFreeCourse && !$hasVipFreeAccess) {
|
||||
$this->error(__('当前没有加入学习的资格'));
|
||||
}
|
||||
|
||||
\app\common\model\course\Course::checkSalesType($courseInfo);
|
||||
|
||||
//判断是否订阅过了
|
||||
$userCourse = $this->SubscriptionModel->getUserCourse($userId,$courseId);
|
||||
if($userCourse){
|
||||
$this->error(__('该课程已经加入学习'));
|
||||
}
|
||||
|
||||
$validityTime = $this->SubscriptionModel->getValidityTime($courseInfo);
|
||||
|
||||
if($validityTime < time()){
|
||||
$this->error(__('该课程有效时间不支持订阅'));
|
||||
}
|
||||
|
||||
//标记 get_type:课程免费时为 free,VIP 权益命中时为 vip
|
||||
$getType = $isFreeCourse ? 'free' : 'vip';
|
||||
|
||||
//添加订阅记录
|
||||
$result = $this->SubscriptionModel->setUserCourse($userId,$courseId,$getType);
|
||||
|
||||
if(!$result){
|
||||
$this->error(__('加入学习失败'));
|
||||
}
|
||||
|
||||
$this->success('加入学习成功');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取我的订阅
|
||||
* @return void
|
||||
*/
|
||||
public function getMySubscription(){
|
||||
$limit = input('limit',10);
|
||||
$page = input('page',1);
|
||||
$type = input('type','all');
|
||||
$list = $this->SubscriptionModel->getMyCourse($this->auth->id,[
|
||||
'limit'=>$limit,
|
||||
'page'=>$page,
|
||||
'type'=>$type
|
||||
]);
|
||||
$this->success('订阅成功',$list);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user