Parcourir la source

Merge branch 'cousre' into liuxiangxin

liuxiangxin il y a 3 mois
Parent
commit
53c286fdce
64 fichiers modifiés avec 4863 ajouts et 67 suppressions
  1. 27 0
      app/Facades/Servers/Aliyun/Oss.php
  2. 2 4
      app/Http/Controllers/Admin/RegimentActive.php
  3. 154 0
      app/Http/Controllers/Admin/VideoAnswer.php
  4. 177 0
      app/Http/Controllers/Admin/VideoCourse.php
  5. 126 0
      app/Http/Controllers/Admin/VideoCourseType.php
  6. 160 0
      app/Http/Controllers/Admin/VideoExamAnswer.php
  7. 164 0
      app/Http/Controllers/Admin/VideoExamQuestion.php
  8. 64 0
      app/Http/Controllers/Admin/VideoExamRecord.php
  9. 160 0
      app/Http/Controllers/Admin/VideoLearnAnswer.php
  10. 185 0
      app/Http/Controllers/Admin/VideoLearnQuestion.php
  11. 65 0
      app/Http/Controllers/Admin/VideoLearnRecord.php
  12. 131 0
      app/Http/Controllers/Admin/VideoQuestion.php
  13. 31 56
      app/Http/Controllers/Api/Recruitment.php
  14. 128 0
      app/Http/Controllers/Api/Video/Course.php
  15. 46 0
      app/Http/Controllers/Api/Video/ExamAnswer.php
  16. 59 0
      app/Http/Controllers/Api/Video/ExamQuestion.php
  17. 158 0
      app/Http/Controllers/Api/Video/ExamRecord.php
  18. 132 0
      app/Http/Controllers/Api/Video/LearnAnswer.php
  19. 48 0
      app/Http/Controllers/Api/Video/LearnQuestion.php
  20. 76 0
      app/Http/Controllers/Api/Video/LearnRecord.php
  21. 49 0
      app/Http/Requests/Admin/Video/Answer.php
  22. 55 0
      app/Http/Requests/Admin/Video/Course.php
  23. 53 0
      app/Http/Requests/Admin/Video/CourseType.php
  24. 55 0
      app/Http/Requests/Admin/Video/ExamQuestion.php
  25. 55 0
      app/Http/Requests/Admin/Video/LearnQuestion.php
  26. 50 0
      app/Http/Requests/Admin/Video/Question.php
  27. 6 0
      app/Models/Traits/Score/BuyType.php
  28. 123 0
      app/Models/Video/Answer.php
  29. 100 0
      app/Models/Video/Course.php
  30. 99 0
      app/Models/Video/CourseType.php
  31. 53 0
      app/Models/Video/ExamAnswer.php
  32. 84 0
      app/Models/Video/ExamQuestion.php
  33. 53 0
      app/Models/Video/ExamRecord.php
  34. 53 0
      app/Models/Video/LearnAnswer.php
  35. 104 0
      app/Models/Video/LearnQuestion.php
  36. 53 0
      app/Models/Video/LearnRecord.php
  37. 103 0
      app/Models/Video/Question.php
  38. 55 0
      app/Servers/Aliyun/Oss.php
  39. 1 0
      composer.json
  40. 55 4
      composer.lock
  41. 24 0
      resources/views/admin/video_answer/add.blade.php
  42. 25 0
      resources/views/admin/video_answer/edit.blade.php
  43. 84 0
      resources/views/admin/video_answer/index.blade.php
  44. 127 0
      resources/views/admin/video_course/add.blade.php
  45. 128 0
      resources/views/admin/video_course/edit.blade.php
  46. 125 0
      resources/views/admin/video_course/index.blade.php
  47. 16 0
      resources/views/admin/video_course_type/add.blade.php
  48. 17 0
      resources/views/admin/video_course_type/edit.blade.php
  49. 71 0
      resources/views/admin/video_course_type/index.blade.php
  50. 86 0
      resources/views/admin/video_exam_answer/index.blade.php
  51. 28 0
      resources/views/admin/video_exam_question/add.blade.php
  52. 29 0
      resources/views/admin/video_exam_question/edit.blade.php
  53. 89 0
      resources/views/admin/video_exam_question/index.blade.php
  54. 78 0
      resources/views/admin/video_exam_record/index.blade.php
  55. 86 0
      resources/views/admin/video_learn_answer/index.blade.php
  56. 39 0
      resources/views/admin/video_learn_question/add.blade.php
  57. 40 0
      resources/views/admin/video_learn_question/edit.blade.php
  58. 91 0
      resources/views/admin/video_learn_question/index.blade.php
  59. 80 0
      resources/views/admin/video_learn_record/index.blade.php
  60. 20 0
      resources/views/admin/video_question/add.blade.php
  61. 21 0
      resources/views/admin/video_question/edit.blade.php
  62. 79 0
      resources/views/admin/video_question/index.blade.php
  63. 45 1
      routes/api.php
  64. 83 2
      routes/web.php

+ 27 - 0
app/Facades/Servers/Aliyun/Oss.php

@@ -0,0 +1,27 @@
+<?php namespace App\Facades\Servers\Aliyun;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * 对象存储
+ * 
+ * @method static string|array signUrl($bucket, $object, $options=['Content-Type'=>'multipart/form-data'] ) 获取签名路径
+ * 
+ * @see \App\Servers\Aliyun\Oss
+ * 
+ * 
+ */
+class Oss extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return '\App\Servers\Aliyun\Oss';
+    }
+}
+
+?>

+ 2 - 4
app/Http/Controllers/Admin/RegimentActive.php

@@ -108,15 +108,14 @@ class RegimentActive extends Auth{
             $data['exceed_people']			= request('exceed_people',0);
             $data['automatic']				= request('automatic',0);
             $data['virtually']				= request('virtually',0);
-            $data['business_id']	        = request('business_id',0);
             $data['status']			        = 1;
             // 核对产品
             $product_res                    = $Model->query()->where([['status','=', 1],['product_id','=', $data['product_id']],['end_time','>=', time()]])->first();
             // 提示
             if ($product_res)               return json_send(['code'=>'error','msg'=>'该产品正在参加拼团活动']);
             // 核对产品
-            $product_res                    = $Product->query()->where([['business_id','=', $data['business_id']],['id','=', $data['product_id']]])->first();
-            if (!$product_res)               return json_send(['code'=>'error','msg'=>'该店铺产品不存在']);
+            $product_res                    = $Product->query()->where([['id','=', $data['product_id']]])->first();
+            if (!$product_res)               return json_send(['code'=>'error','msg'=>'该产品不存在']);
             //核对产品价格
             $productInfo                    = $Product->getOne($data['product_id']);
             // 如果拼团价格大于产品价格
@@ -196,7 +195,6 @@ class RegimentActive extends Auth{
             $data['automatic']				= request('automatic',0);
             $data['virtually']				= request('virtually',0);
             $data['status']			        = 1;
-            $data['business_id']	        = request('business_id',0);
             // 核对产品
             $product_res                    = $Model::query()->where([['id','><', $id],['status','=', 1],['product_id','=', $data['product_id']],['end_time','>=', time()]])->first();
             // 提示

+ 154 - 0
app/Http/Controllers/Admin/VideoAnswer.php

@@ -0,0 +1,154 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Video\Answer as Request;
+use App\Models\Video\Answer as Model;
+use App\Models\Video\Question as Question;
+/**
+ * 灯谜答案
+ *
+ * @author    刘相欣
+ *
+ */
+class VideoAnswer extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','课程习题');
+		$this->assign('breadcrumb2','习题答案');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model,Question $Question){
+		// 接收参数
+		$questionId				= request('question_id','');
+		// 查询条件
+		$map 					= [];
+		// 组合条件
+		if( $questionId )		$map[] = ['question_id','=',$questionId];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('id')->paginate(config('page_num',10));
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 问题列表
+		$questionList			= $Question->query()->get(['id','title'])->toArray();
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('questionList',$questionList);
+		$this->assign('list',$list);
+		// 加载模板
+		return 					$this->fetch();
+    }
+
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add(Request $request,Model $Model,Question $Question){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 接收数据
+			$data['question_id']	= request('question_id',0);
+			$data['value']			= request('value','');
+			// 通过查询
+			$count					= count($Model->getListByQuestion($data['question_id']));
+			// 最多添加4个选项
+			if( $count >= 4 )		return json_send(['code'=>'error','msg'=>'最多添加4个选项']);
+			// 写入数据表
+			$id						= $Model->add($data);
+			// 如果操作失败
+			if( !$id ) 				return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 问题列表
+		$questionList				= $Question->query()->get(['id','title'])->toArray();
+		// 分配数据
+		$this->assign('questionList',$questionList);
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return						$this->fetch(); 
+	}
+
+	/**
+	 * 修改
+	 * 
+	 * */
+	public function edit(Request $request,Model $Model,Question $Question){
+		// 接收参数
+		$id							= request('id',0);
+		// 查询用户
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 修改
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 接收数据
+			$data['question_id']	= request('question_id',0);
+			$data['value']			= request('value','');
+			// 获取当前问题
+			$oldQuestion			= $Model->getOne($data['question_id'],$id,'question_id');
+			// 如果当前选项值,不是当前的问题ID
+			if( $oldQuestion != $data['question_id'] ){
+				// 通过查询
+				$count					= count($Model->getListByQuestion($data['question_id']));
+				// 最多添加4个选项
+				if( $count >= 4 )		return json_send(['code'=>'error','msg'=>'最多添加4个选项']);
+			}
+			// 写入数据表
+			$result					= $Model->edit($id,$data);
+			// 如果操作失败
+			if( !$result ) 			return json_send(['code'=>'error','msg'=>'修改失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
+		}
+		// 错误告知
+		if( !$oldData )				return $this->error('查无数据');
+		// 问题列表
+		$questionList				= $Question->query()->get(['id','title'])->toArray();
+		// 分配数据
+		$this->assign('questionList',$questionList);
+		$this->assign('oldData',$oldData);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return						$this->fetch();
+	}
+
+	/**
+	 * 修改状态
+	 * 
+	 * */
+	public function set_answer(Request $request,Model $Model){
+		// 验证参数
+		$request->scene('set_answer')->validate();
+		// 设置状态
+		$id				= request('id',0);
+		$status			= request('is_answer',0);
+		// 查询用户
+		$oldData		= $Model->where(['id'=>$id])->first();
+		// 如果用户不存在
+		if( !$oldData )	return json_send(['code'=>'error','msg'=>'数据不存在']);
+		// 执行修改
+		$result			= $Model->query()->where([['question_id','=',$oldData['question_id']]])->update(['is_answer'=>0]);
+		// 执行修改
+		$result			= $Model->edit($id,['is_answer'=>$status,'question_id'=>$oldData['question_id']]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,['is_answer'=>$status]);
+		// 告知结果
+		return 			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 177 - 0
app/Http/Controllers/Admin/VideoCourse.php

@@ -0,0 +1,177 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Facades\Servers\Aliyun\Oss;
+use App\Http\Requests\Admin\Video\Course as Request;
+use App\Models\Video\Course as Model;
+use App\Models\Video\CourseType;
+/**
+ * 课程管理
+ *
+ * @author    huanglei
+ *
+ */
+class VideoCourse extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','课程管理');
+		$this->assign('breadcrumb2','课程列表');
+	}
+
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model,CourseType $CourseType){
+		// 接受参数
+		$name					= request('name','');
+		$status					= request('status');
+		$typeId					= request('type_id',0);
+		$startTime				= request('start_time','');
+		$endTime				= request('end_time','');
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $name )				$map[] = ['name','LIKE','%'.$name.'%'];
+		if( $typeId )			$map[] = ['type_id','=',$typeId];
+		if( $startTime )		$map[] = ['insert_time','>=',strtotime($startTime)];
+		if( $endTime )			$map[] = ['insert_time','<=',strtotime($endTime)];
+		if( !is_null($status) )	$map[] = ['status','=',$status];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('id')->paginate(request('limit',config('page_num',10)))->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 类型名称
+			$value['type_name'] = $CourseType->getOne($value['type_id'],'name');
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 获取类型列表
+		$typeList					= $CourseType->getList();
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('typeList',$typeList);
+		$this->assign('list', $list);
+		// 加载模板
+		return					$this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add( Request $request, Model $Model,CourseType $CourseType){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 组合数据
+			$data['thumb']			= request('thumb','');
+			$data['video_src']		= request('video_src','');
+			$data['name']			= request('name','');
+			$data['content']		= request('content','');
+			$data['start_time']		= request('start_time','');
+			$data['end_time']		= request('end_time','');
+			$data['type_id']		= request('type_id',0);
+			$data['start_time']		= $data['start_time'] ? strtotime($data['start_time']) : 0;
+			$data['end_time']		= $data['end_time'] ? strtotime($data['end_time']) : 0;
+			$data['status']			= 1;
+			// 写入
+			$id						= $Model->add($data);
+			// 提示新增失败
+			if( !$id )				return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 获取类型列表
+		$typeList					= $CourseType->getList();
+		// 分配数据
+		$this->assign('crumbs','新增');
+		$this->assign('typeList',$typeList);
+		// 加载模板
+		return 						$this->fetch();
+	}
+	
+	/**
+	 * 编辑
+	 * 
+	 * */
+	public function edit( Request $request, Model $Model,CourseType $CourseType){
+		// 接收参数
+		$id							= request('id',0);
+		// 查询数据
+		$oldData					= $Model->where(['id'=>$id])->first();
+		$oldData					= $oldData ? $oldData->toArray() : [];
+		// 修改
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 组合数据
+			$data['thumb']			= request('thumb','');
+			$data['video_src']		= request('video_src','');
+			$data['name']			= request('name','');
+			$data['content']		= request('content','');
+			$data['start_time']		= request('start_time','');
+			$data['end_time']		= request('end_time','');
+			$data['type_id']		= request('type_id',0);
+			$data['start_time']		= $data['start_time'] ? strtotime($data['start_time']) : 0;
+			$data['end_time']		= $data['end_time'] ? strtotime($data['end_time']) : 0;
+			// 写入
+			$result					= $Model->edit($id,$data);
+			// 提示新增失败
+			if( !$result )			return json_send(['code'=>'error','msg'=>'修改失败']);
+			// 删除结果
+			unset($oldData['content']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
+		}
+		// 如果是没有数据
+		if( !$oldData ) 			return $this->error('查无数据');
+		// 获取类型列表
+		$typeList					= $CourseType->getList();
+		// 分配数据
+		$this->assign('typeList',$typeList);
+		$this->assign('oldData',$oldData);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return 						$this->fetch();
+	}
+
+	/**
+	 * 状态
+	 * 
+	 * */
+	public function set_status( Request $request, Model $Model){
+		// 验证参数
+		
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 查询数据
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 告知结果
+		return			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+	
+	/**
+	 * 获取上传视频签名URL
+	 * 
+	 * */
+	public function get_sign_url()		{
+		// 获取签名URL
+        $signUrl        				= Oss::signUrl('kailin-mp', 'uploads/video/'.admin('uid').'/'.date('Ymd').'/'.uniqid().'.mp4',['Content-Type'=>'']);
+		// 如果签名失败
+		if( !$signUrl )					return json_send(['code'=>'error','msg'=>'生成签名失败']);
+		// 签名异常
+		if( isset($signUrl['error']) )	return json_send(['code'=>'error','msg'=>$signUrl['error']]);
+		// 下发
+		return							json_send(['code'=>'success','msg'=>'获取成功','data'=>['sign_url'=>$signUrl,'video_src'=>str_ireplace('?'.parse_url($signUrl,PHP_URL_QUERY),'',$signUrl)]]);
+	}
+
+}

+ 126 - 0
app/Http/Controllers/Admin/VideoCourseType.php

@@ -0,0 +1,126 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Video\CourseType as Request;
+use App\Models\Video\CourseType as Model;
+
+/**
+ * 课程管理
+ *
+ * @author    huanglei
+ *
+ */
+class VideoCourseType extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','课程管理');
+		$this->assign('breadcrumb2','课程类型');
+	}
+
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model){
+		
+		// 接受参数
+		$name					= request('name','');
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $name )				$map[] = ['name','LIKE','%'.$name.'%'];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('id')->paginate(request('limit',config('page_num',10)))->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list', $list);
+		// 加载模板
+		return					$this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add( Request $request, Model $Model){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 组合数据
+			$data['name']			= request('name','');
+			// 写入
+			$id						= $Model->add($data);
+			// 提示新增失败
+			if( !$id )				return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 分配数据
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return 						$this->fetch();
+	}
+	
+	/**
+	 * 编辑
+	 * 
+	 * */
+	public function edit( Request $request, Model $Model){
+		// 接收参数
+		$id							= request('id',0);
+		// 查询数据
+		$oldData					= $Model->where(['id'=>$id])->first();
+		$oldData					= $oldData ? $oldData->toArray() : [];
+		// 修改
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 组合数据
+			$data['name']			= request('name','');
+			// 写入
+			$result					= $Model->edit($id,$data);
+			// 提示新增失败
+			if( !$result )			return json_send(['code'=>'error','msg'=>'修改失败']);
+			// 删除结果
+			unset($oldData['content']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
+		}
+		// 如果是没有数据
+		if( !$oldData ) 			return $this->error('查无数据');
+		// 分配数据
+		$this->assign('oldData',$oldData);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return 						$this->fetch();
+	}
+
+	/**
+	 * 状态
+	 * 
+	 * */
+	public function set_status( Request $request, Model $Model){
+		// 验证参数
+		
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 查询数据
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 告知结果
+		return			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 160 - 0
app/Http/Controllers/Admin/VideoExamAnswer.php

@@ -0,0 +1,160 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Models\Custom;
+use App\Models\Video\ExamAnswer as Model;
+use App\Models\Video\Course as VideoCourse;
+use App\Models\Video\Answer as VideoAnswer;
+use App\Models\Video\Question as VideoQuestion;
+
+/**
+ * 学习记录
+ *
+ * @author    刘相欣
+ *
+ */
+class VideoExamAnswer extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','课后评测');
+		$this->assign('breadcrumb2','答题记录');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model,VideoCourse $VideoCourse,Custom $Custom,VideoQuestion $VideoQuestion,VideoAnswer $VideoAnswer){
+		// 接收参数
+		$recordId					= request('record_id',0);
+		$courseId					= request('course_id',0);
+		$customCode					= request('custom_code','');
+		$customName					= request('custom_name','');
+		// 转码
+		$customCode					= $Custom->codeToId($customCode);
+		// 查询条件
+		$map 						= [];
+		// 组合条件
+		if( $courseId )				$map[] = ['video_course.id','=',$courseId];
+		if( $recordId )				$map[] = ['video_exam_answer.record_id','=',$recordId];
+		if( $customCode )			$map[] = ['custom.uid','=',$customCode];
+		if( $customName )			$map[] = ['custom.username','LIKE','%'.$customName.'%'];
+		// 查询数据
+		$list						= $Model->query()
+									->join('video_course','video_course.id','=','video_exam_answer.course_id')
+									->join('custom','custom.uid','=','video_exam_answer.custom_uid')
+									->where($map)->select(['video_exam_answer.*','video_course.name as course_name','custom.username as custom_name'])
+									->orderByDesc('id')->paginate(config('page_num',10));
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 时间
+			$value['custom_code']	= $Custom->idToCode($value['custom_uid']);
+			$value['question_title']= $VideoQuestion->getOne($value['question_id'],'title');
+			$value['answer_list'] 	= $VideoAnswer->getListByQuestion($value['question_id']);
+			$value['answer_list'] 	= array_values($value['answer_list']);
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 查询数据
+		$courseList 				= $VideoCourse->query()->orderByDesc('id')->get(['id','name']);
+		// 分配数据
+		$this->assign('list',$list);
+		$this->assign('courseList',$courseList);
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		// 加载模板
+		return 						$this->fetch();
+    }
+
+
+	/**
+	 * 导出表格导入
+	 * 
+	 * */
+	public function down_excel(Model $Model,Custom $Custom,VideoQuestion $VideoQuestion,VideoAnswer $VideoAnswer){
+		// 接收参数
+		$recordId					= request('record_id',0);
+		$courseId					= request('course_id',0);
+		$customCode					= request('custom_code','');
+		$customName					= request('custom_name','');
+		// 转码
+		$customCode					= $Custom->codeToId($customCode);
+		// 查询条件
+		$map 						= [];
+		// 组合条件
+		if( $courseId )				$map[] = ['video_course.id','=',$courseId];
+		if( $recordId )				$map[] = ['video_exam_answer.record_id','=',$recordId];
+		if( $customCode )			$map[] = ['custom.uid','=',$customCode];
+		if( $customName )			$map[] = ['custom.username','LIKE','%'.$customName.'%'];
+		// 查询数据
+		$list						= $Model->query()
+									->join('video_course','video_course.id','=','video_exam_answer.course_id')
+									->join('custom','custom.uid','=','video_exam_answer.custom_uid')
+									->where($map)->select(['video_exam_answer.*','video_course.name as course_name','custom.username as custom_name'])
+									->get()->toArray();
+		$data						= [];
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 时间
+			$value['custom_code']	= $Custom->idToCode($value['custom_uid']);
+			$value['question_title']= $VideoQuestion->getOne($value['question_id'],'title');
+			$value['answer_list'] 	= $VideoAnswer->getListByQuestion($value['question_id']);
+			$value['answer_list'] 	= array_values($value['answer_list']);
+			foreach ( $value['answer_list'] as $k => $v) {
+				if( $v['is_answer'] )  $value['answer_list'][$k]['value'] .= "【答案】";
+			}
+			// 重组
+            $data[$key]             = [
+                'id'		    	=> $value['id'],
+                'course_name'		=> $value['course_name'],
+                'custom_code'		=> $value['custom_code'],
+                'custom_name'		=> $value['custom_name'],
+				'question_title'	=> $value['question_title'],
+				'answer_list'		=> implode("\n",array_column($value['answer_list'],'value') ),
+				'is_answer'			=> $value['is_answer']?'答对':'答错',
+				'get_score'			=> $value['get_score'],
+				'insert_time'		=> date('Y-m-d H:i:s',$value['insert_time'])
+            ];
+			// 重组
+			$list[$key]				= $value;
+		}
+         
+		try {
+			// 去下载
+			$this->toDown($data);
+		} catch (\Throwable $th) {
+			echo $th->getMessage();
+		}
+		
+	}
+
+
+	/**
+	 * 去下载
+	 */
+	private function  toDown($data){
+        try {
+            $config     = ['path' =>public_path().'/uploads/'];
+            $excel      = new \Vtiful\Kernel\Excel($config);
+            $header     = ['ID','课程名称','客户编码','客户昵称','习题题目','习题选项','是否答对','得分','答题时间'];
+            $filePath = $excel->fileName('tutorial01.xlsx', 'sheet1')->header($header)->data($data)->output();
+            $filename   = uniqid().'.xlsx';
+            header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+            header('Content-Disposition: attachment;filename="' . $filename . '"');
+            header('Content-Length: ' . filesize($filePath));
+            header('Content-Transfer-Encoding: binary');
+            header('Cache-Control: must-revalidate');
+            header('Cache-Control: max-age=0');
+            header('Pragma: public');
+            ob_clean();
+            flush();
+            if (copy($filePath, 'php://output') === false) {
+                dd('下载出错');
+            }
+            @unlink($filePath);
+            exit();
+        }catch (\Throwable $th) {
+            return $th->getMessage();
+        }
+	}
+
+}

+ 164 - 0
app/Http/Controllers/Admin/VideoExamQuestion.php

@@ -0,0 +1,164 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Video\ExamQuestion as Request;
+use App\Models\Video\ExamQuestion as Model;
+use App\Models\Video\Course as VideoCourse;
+use App\Models\Video\Question as VideoQuestion;
+
+
+/**
+ * 课程习题
+ *
+ * @author    刘相欣
+ *
+ */
+class VideoExamQuestion extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','课程习题');
+		$this->assign('breadcrumb2','课后习题');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model,VideoCourse $VideoCourse,VideoQuestion $VideoQuestion){
+		// 接收参数
+		$courseId				= request('course_id',0);
+		$questionId				= request('question_id',0);
+		// 查询条件
+		$map 					= [];
+		// 组合条件
+		if( $courseId )			$map[] = ['video_course.id','=',$courseId];
+		if( $questionId )		$map[] = ['video_question.id','=',$questionId];
+		// 查询数据
+		$list					= $Model->query()
+									->join('video_course','video_course.id','=','video_exam_question.course_id')
+									->join('video_question','video_question.id','=','video_exam_question.question_id')
+									->where($map)->select(['video_exam_question.*','video_course.name as course_name','video_question.title as question_title'])
+									->orderBy('video_exam_question.id')->paginate(config('page_num',10));
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 查询数据
+		$courseList 			= $VideoCourse->query()->orderByDesc('id')->get(['id','name']);
+		$questionList 			= $VideoQuestion->query()->orderByDesc('id')->get(['id','title']);
+		// 分配数据
+		$this->assign('list',$list);
+		$this->assign('courseList',$courseList);
+		$this->assign('questionList',$questionList);
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		// 加载模板
+		return 					$this->fetch();
+    }
+
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add(Request $request,Model $Model,VideoCourse $VideoCourse,VideoQuestion $VideoQuestion){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 接收数据
+			$data['course_id']		= request('course_id',0);
+			$data['question_id']	= request('question_id',0);
+			$data['status']			= 1;
+			// 查询
+			$unique					= $Model->where(['course_id'=>$data['course_id'],'question_id'=>$data['question_id']])->first();
+			// 如果存在
+			if( $unique )			return json_send(['code'=>'error','msg'=>'习题已存在']);
+			// 写入数据表
+			$id						= $Model->add($data);
+			// 如果操作失败
+			if( !$id ) 				return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 查询数据
+		$courseList 			= $VideoCourse->query()->orderByDesc('id')->get(['id','name']);
+		$questionList 			= $VideoQuestion->query()->orderByDesc('id')->get(['id','title']);
+		// 分配数据
+		$this->assign('courseList',$courseList);
+		$this->assign('questionList',$questionList);
+		// 分配数据
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return						$this->fetch(); 
+	}
+
+	/**
+	 * 修改
+	 * 
+	 * */
+	public function edit(Request $request,Model $Model,VideoCourse $VideoCourse,VideoQuestion $VideoQuestion){
+		// 接收参数
+		$id							= request('id',0);
+		// 查询用户
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 修改
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 接收数据
+			$data['course_id']		= request('course_id',0);
+			$data['question_id']	= request('question_id',0);
+			// 查询
+			$unique					= $Model->where([['course_id','=',$data['course_id']],['question_id','=',$data['question_id']],['id','<>',$id]])->first();
+			// 如果存在
+			if( $unique )			return json_send(['code'=>'error','msg'=>'习题已存在']);
+			// 写入数据表
+			$result					= $Model->edit($id,$data);
+			// 如果操作失败
+			if( !$result ) 			return json_send(['code'=>'error','msg'=>'修改失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
+		}
+		// 错误告知
+		if( !$oldData )				return $this->error('查无数据');
+		// 查询数据
+		$courseList 				= $VideoCourse->query()->orderByDesc('id')->get(['id','name']);
+		$questionList 				= $VideoQuestion->query()->orderByDesc('id')->get(['id','title']);
+		// 分配数据
+		$this->assign('oldData',$oldData);
+		$this->assign('courseList',$courseList);
+		$this->assign('questionList',$questionList);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return						$this->fetch();
+	}
+
+	/**
+	 * 修改状态
+	 * 
+	 * */
+	public function set_status(Request $request,Model $Model){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 设置状态
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 查询用户
+		$oldData		= $Model->where(['id'=>$id])->first();
+		// 如果用户不存在
+		if( !$oldData )	return json_send(['code'=>'error','msg'=>'数据不存在']);
+		// 执行修改
+		$result			= $Model->edit($id,['status'=>$status,'course_id'=>$oldData['course_id']]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,['status'=>$status]);
+		// 告知结果
+		return 			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 64 - 0
app/Http/Controllers/Admin/VideoExamRecord.php

@@ -0,0 +1,64 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Models\Custom;
+use App\Models\Video\ExamRecord as Model;
+use App\Models\Video\Course as VideoCourse;
+
+
+/**
+ * 测评记录
+ *
+ * @author    刘相欣
+ *
+ */
+class VideoExamRecord extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','课程关联');
+		$this->assign('breadcrumb2','测评记录');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model,VideoCourse $VideoCourse,Custom $Custom){
+		// 接收参数
+		$courseId				= request('course_id',0);
+		$customCode				= request('custom_code','');
+		$customName				= request('custom_name','');
+		// 转码
+		$customCode				= $Custom->codeToId($customCode);
+		// 查询条件
+		$map 					= [];
+		// 组合条件
+		if( $courseId )			$map[] = ['video_course.id','=',$courseId];
+		if( $customCode )		$map[] = ['custom.uid','=',$customCode];
+		if( $customName )		$map[] = ['custom.username','LIKE','%'.$customName.'%'];
+		// 查询数据
+		$list					= $Model->query()
+									->join('video_course','video_course.id','=','video_exam_record.course_id')
+									->join('custom','custom.uid','=','video_exam_record.custom_uid')
+									->where($map)->select(['video_exam_record.*','video_course.name as course_name','custom.username as custom_name'])
+									->orderByDesc('id')->paginate(config('page_num',10));
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 时间
+			$value['custom_code']	 = $Custom->idToCode($value['custom_uid']);
+			$value['right_ratio']	 = $value['question_total'] ? number_format(($value['isanswer_total'] / $value['question_total'])*100 ,2) : 0;
+			$value['exam_time'] 	 = str_pad((floor($value['exam_time'] / 60)),2, '0', STR_PAD_LEFT) .':'. str_pad(($value['exam_time'] % 60),2, '0', STR_PAD_LEFT);
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 查询数据
+		$courseList 			= $VideoCourse->query()->orderByDesc('id')->get(['id','name']);
+		// 分配数据
+		$this->assign('list',$list);
+		$this->assign('courseList',$courseList);
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		// 加载模板
+		return 					$this->fetch();
+    }
+
+}

+ 160 - 0
app/Http/Controllers/Admin/VideoLearnAnswer.php

@@ -0,0 +1,160 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Models\Custom;
+use App\Models\Video\LearnAnswer as Model;
+use App\Models\Video\Course as VideoCourse;
+use App\Models\Video\Answer as VideoAnswer;
+use App\Models\Video\Question as VideoQuestion;
+
+/**
+ * 学习记录
+ *
+ * @author    刘相欣
+ *
+ */
+class VideoLearnAnswer extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','课中习题');
+		$this->assign('breadcrumb2','答题记录');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model,VideoCourse $VideoCourse,Custom $Custom,VideoQuestion $VideoQuestion,VideoAnswer $VideoAnswer){
+		// 接收参数
+		$recordId					= request('record_id',0);
+		$courseId					= request('course_id',0);
+		$customCode					= request('custom_code','');
+		$customName					= request('custom_name','');
+		// 转码
+		$customCode					= $Custom->codeToId($customCode);
+		// 查询条件
+		$map 						= [];
+		// 组合条件
+		if( $courseId )				$map[] = ['video_course.id','=',$courseId];
+		if( $recordId )				$map[] = ['video_learn_answer.record_id','=',$recordId];
+		if( $customCode )			$map[] = ['custom.uid','=',$customCode];
+		if( $customName )			$map[] = ['custom.username','LIKE','%'.$customName.'%'];
+		// 查询数据
+		$list						= $Model->query()
+									->join('video_course','video_course.id','=','video_learn_answer.course_id')
+									->join('custom','custom.uid','=','video_learn_answer.custom_uid')
+									->where($map)->select(['video_learn_answer.*','video_course.name as course_name','custom.username as custom_name'])
+									->orderByDesc('id')->paginate(config('page_num',10));
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 时间
+			$value['custom_code']	= $Custom->idToCode($value['custom_uid']);
+			$value['question_title']= $VideoQuestion->getOne($value['question_id'],'title');
+			$value['answer_list'] 	= $VideoAnswer->getListByQuestion($value['question_id']);
+			$value['answer_list'] 	= array_values($value['answer_list']);
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 查询数据
+		$courseList 				= $VideoCourse->query()->orderByDesc('id')->get(['id','name']);
+		// 分配数据
+		$this->assign('list',$list);
+		$this->assign('courseList',$courseList);
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		// 加载模板
+		return 						$this->fetch();
+    }
+
+	/**
+	 * 导出表格导入
+	 * 
+	 * */
+	public function down_excel(Model $Model,Custom $Custom,VideoQuestion $VideoQuestion,VideoAnswer $VideoAnswer){
+		// 接收参数
+		$recordId					= request('record_id',0);
+		$courseId					= request('course_id',0);
+		$customCode					= request('custom_code','');
+		$customName					= request('custom_name','');
+		// 转码
+		$customCode					= $Custom->codeToId($customCode);
+		// 查询条件
+		$map 						= [];
+		// 组合条件
+		if( $courseId )				$map[] = ['video_course.id','=',$courseId];
+		if( $recordId )				$map[] = ['video_learn_answer.record_id','=',$recordId];
+		if( $customCode )			$map[] = ['custom.uid','=',$customCode];
+		if( $customName )			$map[] = ['custom.username','LIKE','%'.$customName.'%'];
+		// 查询数据
+		$list						= $Model->query()
+									->join('video_course','video_course.id','=','video_learn_answer.course_id')
+									->join('custom','custom.uid','=','video_learn_answer.custom_uid')
+									->where($map)->select(['video_learn_answer.*','video_course.name as course_name','custom.username as custom_name'])
+									->get()->toArray();
+		$data						= [];
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 时间
+			$value['custom_code']	= $Custom->idToCode($value['custom_uid']);
+			$value['question_title']= $VideoQuestion->getOne($value['question_id'],'title');
+			$value['answer_list'] 	= $VideoAnswer->getListByQuestion($value['question_id']);
+			$value['answer_list'] 	= array_values($value['answer_list']);
+			foreach ( $value['answer_list'] as $k => $v) {
+				if( $v['is_answer'] )  $value['answer_list'][$k]['value'] .= "【答案】";
+			}
+			// 重组
+            $data[$key]             = [
+                'id'		    	=> $value['id'],
+                'course_name'		=> $value['course_name'],
+                'custom_code'		=> $value['custom_code'],
+                'custom_name'		=> $value['custom_name'],
+				'question_title'	=> $value['question_title'],
+				'answer_list'		=> implode("\n",array_column($value['answer_list'],'value') ),
+				'is_answer'			=> $value['is_answer']?'答对':'答错',
+				'get_score'			=> $value['get_score'],
+				'insert_time'		=> date('Y-m-d H:i:s',$value['insert_time'])
+            ];
+			// 重组
+			$list[$key]				= $value;
+		}
+         
+		try {
+			// 去下载
+			$this->toDown($data);
+		} catch (\Throwable $th) {
+			echo $th->getMessage();
+		}
+		
+	}
+
+
+	/**
+	 * 去下载
+	 */
+	private function  toDown($data){
+        try {
+            $config     = ['path' =>public_path().'/uploads/'];
+            $excel      = new \Vtiful\Kernel\Excel($config);
+            $header     = ['ID','课程名称','客户编码','客户昵称','习题题目','习题选项','是否答对','得分','答题时间'];
+            $filePath = $excel->fileName('tutorial01.xlsx', 'sheet1')->header($header)->data($data)->output();
+            $filename   = uniqid().'.xlsx';
+            header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+            header('Content-Disposition: attachment;filename="' . $filename . '"');
+            header('Content-Length: ' . filesize($filePath));
+            header('Content-Transfer-Encoding: binary');
+            header('Cache-Control: must-revalidate');
+            header('Cache-Control: max-age=0');
+            header('Pragma: public');
+            ob_clean();
+            flush();
+            if (copy($filePath, 'php://output') === false) {
+                dd('下载出错');
+            }
+            @unlink($filePath);
+            exit();
+        }catch (\Throwable $th) {
+            return $th->getMessage();
+        }
+	}
+
+
+}

+ 185 - 0
app/Http/Controllers/Admin/VideoLearnQuestion.php

@@ -0,0 +1,185 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Video\LearnQuestion as Request;
+use App\Models\Video\LearnQuestion as Model;
+use App\Models\Video\Course as VideoCourse;
+use App\Models\Video\Question as VideoQuestion;
+
+
+/**
+ * 课程习题
+ *
+ * @author    刘相欣
+ *
+ */
+class VideoLearnQuestion extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','课程习题');
+		$this->assign('breadcrumb2','课中习题');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model,VideoCourse $VideoCourse,VideoQuestion $VideoQuestion){
+		// 接收参数
+		$courseId				= request('course_id',0);
+		$questionId				= request('question_id',0);
+		// 查询条件
+		$map 					= [];
+		// 组合条件
+		if( $courseId )			$map[] = ['video_course.id','=',$courseId];
+		if( $questionId )		$map[] = ['video_question.id','=',$questionId];
+		// 查询数据
+		$list					= $Model->query()
+									->join('video_course','video_course.id','=','video_learn_question.course_id')
+									->join('video_question','video_question.id','=','video_learn_question.question_id')
+									->where($map)->select(['video_learn_question.*','video_course.name as course_name','video_question.title as question_title'])
+									->orderBy('video_learn_question.play_time')->paginate(config('page_num',10));
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 出题时间
+			$value['play_time'] = str_pad((floor($value['play_time'] / 60)),2, '0', STR_PAD_LEFT) .':'. str_pad(($value['play_time'] % 60),2, '0', STR_PAD_LEFT);
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 查询数据
+		$courseList 			= $VideoCourse->query()->orderByDesc('id')->get(['id','name']);
+		$questionList 			= $VideoQuestion->query()->orderByDesc('id')->get(['id','title']);
+		// 分配数据
+		$this->assign('list',$list);
+		$this->assign('courseList',$courseList);
+		$this->assign('questionList',$questionList);
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		// 加载模板
+		return 					$this->fetch();
+    }
+
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add(Request $request,Model $Model,VideoCourse $VideoCourse,VideoQuestion $VideoQuestion){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 接收数据
+			$data['course_id']		= request('course_id',0);
+			$data['question_id']	= request('question_id',0);
+			$minute					= request('minute',0);
+			$second					= request('second',0);
+			$data['play_time']		= ($minute * 60 ) + $second;
+			$data['status']			= 1;
+			// 查询
+			$unique					= $Model->where(['course_id'=>$data['course_id'],'question_id'=>$data['question_id']])->first();
+			// 如果存在
+			if( $unique )			return json_send(['code'=>'error','msg'=>'习题已存在']);
+			// 查询
+			$unique					= $Model->where(['course_id'=>$data['course_id'],['play_time','=',$data['play_time']]])->first();
+			// 如果存在
+			if( $unique )			return json_send(['code'=>'error','msg'=>'该时间已设置问题']);
+			// 写入数据表
+			$id						= $Model->add($data);
+			// 如果操作失败
+			if( !$id ) 				return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 查询数据
+		$courseList 			= $VideoCourse->query()->orderByDesc('id')->get(['id','name']);
+		$questionList 			= $VideoQuestion->query()->orderByDesc('id')->get(['id','title']);
+		// 分配数据
+		$this->assign('courseList',$courseList);
+		$this->assign('questionList',$questionList);
+		// 分配数据
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return						$this->fetch(); 
+	}
+
+	/**
+	 * 修改
+	 * 
+	 * */
+	public function edit(Request $request,Model $Model,VideoCourse $VideoCourse,VideoQuestion $VideoQuestion){
+		// 接收参数
+		$id							= request('id',0);
+		// 查询用户
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 修改
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 接收数据
+			$data['course_id']		= request('course_id',0);
+			$data['question_id']	= request('question_id',0);
+			$minute					= request('minute',0);
+			$second					= request('second',0);
+			$data['play_time']		= ($minute * 60 ) + $second;
+			// 查询
+			$unique					= $Model->where([['course_id','=',$data['course_id']],['question_id','=',$data['question_id']],['id','<>',$id]])->first();
+			// 如果存在
+			if( $unique )			return json_send(['code'=>'error','msg'=>'习题已存在']);
+			// 查询
+			$unique					= $Model->where(['course_id'=>$data['course_id'],['play_time','=',$data['play_time']],['id','<>',$id]])->first();
+			// 如果存在
+			if( $unique )			return json_send(['code'=>'error','msg'=>'该时间已设置问题']);
+			// 写入数据表
+			$result					= $Model->edit($id,$data);
+			// 如果操作失败
+			if( !$result ) 			return json_send(['code'=>'error','msg'=>'修改失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
+		}
+		// 错误告知
+		if( !$oldData )				return $this->error('查无数据');
+		// 数据处理
+		$minute						= request('minute',0);
+		$second						= request('second',0);
+		$oldData['minute']			= str_pad(floor($oldData['play_time'] / 60),2, '0', STR_PAD_LEFT);
+		$oldData['second']			= str_pad(($oldData['play_time'] % 60),2, '0', STR_PAD_LEFT);
+		// 查询数据
+		$courseList 				= $VideoCourse->query()->orderByDesc('id')->get(['id','name']);
+		$questionList 				= $VideoQuestion->query()->orderByDesc('id')->get(['id','title']);
+		// 分配数据
+		$this->assign('oldData',$oldData);
+		$this->assign('courseList',$courseList);
+		$this->assign('questionList',$questionList);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return						$this->fetch();
+	}
+
+	/**
+	 * 修改状态
+	 * 
+	 * */
+	public function set_status(Request $request,Model $Model){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 设置状态
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 查询用户
+		$oldData		= $Model->where(['id'=>$id])->first();
+		// 如果用户不存在
+		if( !$oldData )	return json_send(['code'=>'error','msg'=>'数据不存在']);
+		// 执行修改
+		$result			= $Model->edit($id,['status'=>$status,'course_id'=>$oldData['course_id']]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,['status'=>$status]);
+		// 告知结果
+		return 			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 65 - 0
app/Http/Controllers/Admin/VideoLearnRecord.php

@@ -0,0 +1,65 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Models\Custom;
+use App\Models\Video\LearnRecord as Model;
+use App\Models\Video\Course as VideoCourse;
+
+
+/**
+ * 学习记录
+ *
+ * @author    刘相欣
+ *
+ */
+class VideoLearnRecord extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','课程关联');
+		$this->assign('breadcrumb2','学习记录');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model,VideoCourse $VideoCourse,Custom $Custom){
+		// 接收参数
+		$courseId				= request('course_id',0);
+		$customCode				= request('custom_code','');
+		$customName				= request('custom_name','');
+		// 转码
+		$customCode				= $Custom->codeToId($customCode);
+		// 查询条件
+		$map 					= [];
+		// 组合条件
+		if( $courseId )			$map[] = ['video_course.id','=',$courseId];
+		if( $customCode )		$map[] = ['custom.uid','=',$customCode];
+		if( $customName )		$map[] = ['custom.username','LIKE','%'.$customName.'%'];
+		// 查询数据
+		$list					= $Model->query()
+									->join('video_course','video_course.id','=','video_learn_record.course_id')
+									->join('custom','custom.uid','=','video_learn_record.custom_uid')
+									->where($map)->select(['video_learn_record.*','video_course.name as course_name','custom.username as custom_name'])
+									->orderByDesc('id')->paginate(config('page_num',10));
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 时间
+			$value['custom_code']	 = $Custom->idToCode($value['custom_uid']);
+			$value['right_ratio']	 = $value['question_total'] ? number_format(($value['isanswer_total'] / $value['question_total'])*100 ,2) : 0;
+			$value['video_inittime'] = str_pad((floor($value['video_inittime'] / 60)),2, '0', STR_PAD_LEFT) .':'. str_pad(($value['video_inittime'] % 60),2, '0', STR_PAD_LEFT);
+			$value['video_lasttime'] = str_pad((floor($value['video_lasttime'] / 60)),2, '0', STR_PAD_LEFT) .':'. str_pad(($value['video_lasttime'] % 60),2, '0', STR_PAD_LEFT);
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 查询数据
+		$courseList 			= $VideoCourse->query()->orderByDesc('id')->get(['id','name']);
+		// 分配数据
+		$this->assign('list',$list);
+		$this->assign('courseList',$courseList);
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		// 加载模板
+		return 					$this->fetch();
+    }
+
+}

+ 131 - 0
app/Http/Controllers/Admin/VideoQuestion.php

@@ -0,0 +1,131 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Video\Question as Request;
+use App\Models\Video\Question as Model;
+
+/**
+ * 课程习题
+ *
+ * @author    刘相欣
+ *
+ */
+class VideoQuestion extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','课程习题');
+		$this->assign('breadcrumb2','习题题目');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model){
+		// 接收参数
+		$name					= request('title','');
+		// 查询条件
+		$map 					= [];
+		// 组合条件
+		if( $name )				$map[] = ['title','=',$name];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('id')->paginate(config('page_num',10));
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list',$list);
+		// 加载模板
+		return 					$this->fetch();
+    }
+
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add(Request $request,Model $Model){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 接收数据
+			$data['title']			= request('title','');
+			$data['score']			= request('score',0);
+			$data['status']			= 1;
+			// 写入数据表
+			$id						= $Model->add($data);
+			// 如果操作失败
+			if( !$id ) 				return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 分配数据
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return						$this->fetch(); 
+	}
+
+	/**
+	 * 修改
+	 * 
+	 * */
+	public function edit(Request $request,Model $Model){
+		// 接收参数
+		$id							= request('id',0);
+		// 查询用户
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 修改
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 接收数据
+			$data['title']			= request('title','');
+			$data['score']			= request('score',0);
+			// 写入数据表
+			$result					= $Model->edit($id,$data);
+			// 如果操作失败
+			if( !$result ) 			return json_send(['code'=>'error','msg'=>'修改失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
+		}
+		// 错误告知
+		if( !$oldData )				return $this->error('查无数据');
+		// 分配数据
+		$this->assign('oldData',$oldData);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return						$this->fetch();
+	}
+
+	/**
+	 * 修改状态
+	 * 
+	 * */
+	public function set_status(Request $request,Model $Model){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 设置状态
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 查询用户
+		$oldData		= $Model->where(['id'=>$id])->first();
+		// 如果用户不存在
+		if( !$oldData )	return json_send(['code'=>'error','msg'=>'数据不存在']);
+		// 执行修改
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,['status'=>$status]);
+		// 告知结果
+		return 			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 31 - 56
app/Http/Controllers/Api/Recruitment.php

@@ -22,69 +22,44 @@ class Recruitment extends Api{
      * 获取拉新活动			/api/recruitment/get_info
      *
      * */
-    public function get_info(Model $Model,Custom $Custom,RecruitmentPrizeRecord $RecruitmentPrizeRecord,RecruitmentRecord $RecruitmentRecord,Tags $WeiBanTags){
+    public function get_info(Model $Model,Custom $Custom,Tags $WeiBanTags){
         // 接口验签
         // $this->verify_sign();
         // 验证登录
         $uid                    		= $this->checkLogin();
-        // 查询数据
         // 获取客户城市ID
         $custom							= $Custom->getOne($uid);
         //查询拉新活动
         if( !$custom['city_id'] )		return json_send(['code'=>'error','msg'=>'请选择所在城市后下单','data'=>['error'=>'请选择所在城市后下单']]);
         // 获取城市ID
-        $cityId							= (string)$custom['city_id'];
+        $cityId							= $custom['city_id'];
         // 查询用户标签
-        $tags							= $WeiBanTags->getListByWeibanExtid($custom['weiban_extid']);
-        $time                           =   time();
-        $select                         = [
-            ['start_time','<=',$time],
-            ['end_time','>',$time],
-            ['status','=',0],
-        ];
-        $activeList                     = $Model::query()->whereRaw("find_in_set('$cityId', city_ids)")->where($select)->get()->toArray();
-        $activeInfo         =   [];
-        if ($activeList) {
-            foreach ($activeList as $active) {
-                $allowJoin = 0;
-                if ($active['tag_scope']) {
-                    // 解析数组
-                    $tag_scope = explode(',', $active['tag_scope']);
-                    // 标签范围限定时,默认不能参与
-                    // 判断标签是不是存在
-                    if ($tags) {
-                        foreach ($tags as $v) {
-                            // 标签范围内,允许参加
-                            if (in_array($v['name'], $tag_scope)) $allowJoin = 1;
-                        }
-                    }
-                }else{
-                    $allowJoin = 1;
-                }
-                if ($active['tag_except']) {
-                    // 解析数组
-                    $tag_except = explode(',', $active['tag_except']);
-                    // 标签范围限定时,默认不能参与
-                    $allowJoin = 0;
-                    // 判断标签是不是存在
-                    if ($tags) {
-                        foreach ($tags as $v) {
-                            // 标签范围内,允许参加
-                            if (in_array($v['name'], $tag_except)) $allowJoin = 0;
-                        }
-                    }
-                }
-                if ($allowJoin) {
-                    $activeInfo         =   $active;
-                    break;
-                }
-            }
+        $tagsList						= $WeiBanTags->getListByWeibanExtid($custom['weiban_extid']);
+        $tagsList                       = array_column($tagsList,'name');
+        // 查询数据
+        $map                            = [['start_time','<=',time()], ['end_time','>',time()],['status','=',0]];
+        // 查询数据
+        $activeList                     = $Model->query()->where($map)->get(['id','name','banner_img','start_time','end_time','status','city_ids','tag_except','tag_scope','active_rule'])->toArray();
+        // 获取参数
+        $activeInfo                     = [];
+        // 循环处理活动数据
+        foreach ( $activeList as $active ) {
+            // 如果城市限制并且不在在城市范围内,不允许参加
+            if ( $active['city_ids'] && !in_array($cityId,explode(',',$active['city_ids'])) ) continue;
+            // 判断标签限制并且不在标签限制范围内,不允许参加
+			if( $active['tag_scope'] && !array_intersect(explode(',',$active['tag_scope']),$tagsList) ) continue;
+			// 判断标签排除限制并且在标签排除范围内,不允许参加
+			if( $active['tag_except'] && array_intersect(explode(',',$active['tag_except']),$tagsList) )  continue;
+            // 获取活动信息
+            $activeInfo                 = $active;
         }
-        if ($activeInfo){
-            $activeInfo['start_time']       =   date('Y-m-d H:i:s',$activeInfo['start_time']);
-            $activeInfo['end_time']         =   date('Y-m-d H:i:s',$activeInfo['end_time']);
-            $activeInfo['banner_img']       =   path_compat($activeInfo['banner_img']);
+        // 如果存在活动信息
+        if ( $activeInfo )              {
+            $activeInfo['start_time']   = date('Y-m-d H:i:s',$activeInfo['start_time']);
+            $activeInfo['end_time']     = date('Y-m-d H:i:s',$activeInfo['end_time']);
+            $activeInfo['banner_img']   = $activeInfo['banner_img'] ? path_compat($activeInfo['banner_img']) : '';
         }
+        // 返回结果
         return							json_send(['code'=>'success','msg'=>'获取成功','data'=>$activeInfo]);
     }
 
@@ -103,11 +78,11 @@ class Recruitment extends Api{
         $map						= [['recruitment_prize_record.custom_uid','=',$uid]];
         // 查询数据
         $Paginator					= $recruitmentPrizeRecord->query()
-            ->join('recruitment_record','recruitment_record.id','=','recruitment_prize_record.recruitment_record_id')
-            ->join('custom','custom.uid','=','recruitment_record.new_uid')
-            ->where($map)
-            ->orderByDesc('id')
-            ->paginate($limit,['recruitment_prize_record.id','recruitment_prize_record.prize_type','recruitment_prize_record.prize','recruitment_prize_record.type','recruitment_prize_record.custom_uid','recruitment_prize_record.insert_time','recruitment_prize_record.recruitment_record_id','custom.username']);
+                                    ->join('recruitment_record','recruitment_record.id','=','recruitment_prize_record.recruitment_record_id')
+                                    ->join('custom','custom.uid','=','recruitment_record.new_uid')
+                                    ->where($map)
+                                    ->orderByDesc('id')
+                                    ->paginate($limit,['recruitment_prize_record.id','recruitment_prize_record.prize_type','recruitment_prize_record.prize','recruitment_prize_record.type','recruitment_prize_record.custom_uid','recruitment_prize_record.insert_time','recruitment_prize_record.recruitment_record_id','custom.username']);
         // 重置数据
         $list						= [];
         // 获取数据

+ 128 - 0
app/Http/Controllers/Api/Video/Course.php

@@ -0,0 +1,128 @@
+<?php namespace App\Http\Controllers\Api\Video;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\Video\Course as Model;
+use App\Models\Video\LearnRecord;
+use App\Models\Video\CourseType;
+use App\Models\Video\LearnQuestion;
+use Illuminate\Support\Facades\DB;
+use App\Models\Video\Answer as VideoAnswer;
+use App\Models\Video\Question as VideoQuestion;
+use App\Models\Video\ExamRecord;
+/**
+ * 课程
+ *
+ * @author    刘相欣
+ *
+ */
+class Course extends Api{
+	
+
+	/**
+	 * 获取课程列表		/api/video_course/get_list
+	 * 
+	 */
+	public function get_list(Model $Model,LearnRecord $LearnRecord,CourseType $CourseType,ExamRecord $ExamRecord){
+		// 检查登录
+		$uid 						= $this->checkLogin();
+		// 查询条件
+		$map 						= [['status','=','0'],['start_time','<=',time()],['end_time','>=',time()]];
+		// 查询课程数据
+		$Paginator					= $Model->query()->where($map)->orderByDesc('id')->select(['id','name','type_id','thumb','end_time'])->paginate(request('limit',config('page_num',10)));
+		// 获取用户学习记录
+		$record 					= $LearnRecord->query()->where([['custom_uid','=',$uid]])->groupBy('course_id')->select(['course_id',DB::raw('max(`status`) as status')])->get()->toArray();
+		// 获取报告
+		$report						= $ExamRecord->query()->where([['custom_uid','=',$uid],['status','=',1]])->groupBy('course_id')->pluck('id','course_id')->toArray();
+		// 记录列表
+		$recordList 				= [];
+		// 以课程重组课程状态
+		foreach ($record as $key => $value) {
+			// 重组
+			$recordList[$value['course_id']] = $value['status'];
+		}
+		// 循环处理数据
+		foreach ($Paginator as $key => $value) {
+			// 类型名称
+			$value['type_name'] 	= (string) $CourseType->getOne($value['type_id'],'name');
+			// 如果没有缩略图,使用海报图
+			$value['thumb']			= path_compat($value['thumb']);
+			// 用户学习状态
+			$value['learn_status']	= isset($recordList[$value['id']]) ? $recordList[$value['id']] : -1;
+			// 学习报告
+			$value['report_id']		= isset($report[$value['id']]) ? $report[$value['id']] : 0;
+			// 结束时间
+		    $value['end_time']   	= date('Y-m-d H:i',$value['end_time']);
+			// 重组
+			$Paginator[$key]		= $value;
+		}
+		// 获取数据
+		$data['total']				= $Paginator->total();
+		$data['current_page']		= $Paginator->currentPage();
+		$data['per_page']			= $Paginator->perPage();
+		$data['last_page']			= $Paginator->lastPage();
+		$data['data']				= $Paginator->items();
+		// 分配数据
+		return						json_send(['code'=>'success','msg'=>'列表数据','data'=>$data]);
+    }
+	/**
+	 * 课程详情		/api/video_course/get_detail
+	 * 
+	 * */
+    public function get_detail(Model $Model,LearnRecord $LearnRecord,LearnQuestion $LearnQuestion,VideoQuestion $VideoQuestion,VideoAnswer $VideoAnswer){
+		// 检查登录
+		$uid 							= $this->checkLogin();
+		// 接受参数
+		$id								= request('id',0);
+		// 用户是否点赞
+		if( !$id )						return json_send(['code'=>'error','msg'=>'课程ID不能为空']);
+		// 获取旧数据
+        $courseData            			= $Model->query()->where([['status','=',0]])->find($id,['id','name','thumb','video_src','content','start_time','end_time','insert_time']);
+		// 用户是否点赞
+		if( !$courseData )				return json_send(['code'=>'error','msg'=>'课程不存在或者已下架']);
+		// 转数组
+		$courseData						= $courseData->toArray();
+		// 用户是否点赞和推荐
+		$courseData['thumb']			= $courseData['thumb'] ? path_compat($courseData['thumb']) : '';
+		// 获取用户学习进度
+		$courseData['inittime'] 		= 0;//(int)$LearnRecord->query()->where([['course_id','=',$id],['custom_uid','=',$uid],['status','=',0]])->orderByDesc('id')->value('video_lasttime');
+		// 查询是不是有记录在使用中
+		$oldRecordId			 		= $LearnRecord->query()->where([['custom_uid','=',$uid],['course_id','=',$id],['status','=',0]])->value('id');
+		// 查询课程数据
+		$questionList					= $LearnQuestion->getList($id);
+		// 以时间排序
+		$questionList					= array_sort($questionList,'play_time',SORT_ASC);
+		// 获取数据
+		foreach ($questionList as $key => $value) {
+			# 获取习题数据
+			$value['question_title']	= $VideoQuestion->getOne($value['question_id'],'title');
+			$value['answer_list'] 		= $VideoAnswer->getListByQuestion($value['question_id']);
+			$value['answer_list'] 		= array_values($value['answer_list']);
+			// 如果没有题目选项,删除
+			if( !$value['answer_list'] ){
+				// 如果没有题目选项,删除
+				unset($questionList[$key]);
+				continue;
+			}
+			// 重组
+			$questionList[$key]			= $value;
+		}
+		// 习题列表
+		$courseData['question_list']	= array_values($questionList);
+		// 学习状态
+		$courseData['learn_status']		= (int)$LearnRecord->query()->where([['custom_uid','=',$uid],['course_id','=',$id]])->value(DB::raw('max(`status`) as status'));
+		// 接收参数
+		$data['custom_uid']				= $uid;
+		$data['course_id']				= $id;
+		$data['start_time']				= time();
+		$data['video_inittime']			= $courseData['inittime'];
+		$data['video_lasttime']			= $courseData['inittime'];
+		$data['question_total']			= count($questionList);
+		// 新增记录
+		$courseData['record_id']		= $oldRecordId ? $LearnRecord->edit($oldRecordId,$data) : $LearnRecord->add($data);
+		// 如果记录失败
+		if( !$courseData['record_id'] )	return json_send(['code'=>'error','msg'=>'获取详情失败,请重试']);
+		// 返回结果
+		return							json_send(['code'=>'success','msg'=>'获取成功','data'=>$courseData]);
+	}
+
+}

+ 46 - 0
app/Http/Controllers/Api/Video/ExamAnswer.php

@@ -0,0 +1,46 @@
+<?php namespace App\Http\Controllers\Api\Video;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\Video\ExamAnswer as Model;
+use App\Models\Video\Answer as VideoAnswer;
+use App\Models\Video\Question as VideoQuestion;
+
+/**
+ * 课程
+ *
+ * @author    刘相欣
+ *
+ */
+class ExamAnswer extends Api{
+	
+    
+    /**
+     * 获取答题记录      /api/video_learn_answer/get_list
+     * 
+     */
+    public function get_list(Model $Model,VideoQuestion $VideoQuestion,VideoAnswer $VideoAnswer){
+        // 用户登录
+        $uid                        = $this->checkLogin();
+        // 接收参数
+        $recordId                   = request('record_id',0);
+        // 如果不是课中习题
+        if( !$recordId )            return json_send(['code'=>'error','msg'=>'请选择评测记录']);
+        // 查询答题记录
+        $answerList                 = $Model->query()
+                                    ->where([['custom_uid','=',$uid],['record_id','=',$recordId]])
+                                    ->select(['id','record_id','course_id','question_id','answer_id','is_answer','get_score'])
+                                    ->get()->toArray();
+        // 循环答题
+        foreach ($answerList as $key => $value) {
+            // 题目标题
+            $value['question_title']= $VideoQuestion->getOne($value['question_id'],'title');
+			$value['answer_list'] 	= $VideoAnswer->getListByQuestion($value['question_id']);
+			$value['answer_list'] 	= array_values($value['answer_list']);
+            // 重组
+			$answerList[$key]		= $value;
+        }
+        // 返回结果
+        return                      json_send(['code'=>'success','msg'=>'获取成功','data'=>$answerList]);
+    }
+
+}

+ 59 - 0
app/Http/Controllers/Api/Video/ExamQuestion.php

@@ -0,0 +1,59 @@
+<?php namespace App\Http\Controllers\Api\Video;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\Video\Answer as VideoAnswer;
+use App\Models\Video\Question as VideoQuestion;
+use App\Models\Video\ExamQuestion as Model;
+use App\Models\Video\ExamRecord;
+/**
+ * 课程
+ *
+ * @author    刘相欣
+ *
+ */
+class ExamQuestion extends Api{
+	
+    /**
+     * 获取课后习题列表      /api/video_exam_question/get_list
+     * 
+     */
+    public function get_list(Model $Model,VideoQuestion $VideoQuestion,VideoAnswer $VideoAnswer,ExamRecord $ExamRecord){
+        // 用户登录
+        $uid                        = $this->checkLogin();
+        // 接收参数
+        $data['course_id']			= request('course_id',0);
+        $data['custom_uid']			= $uid;
+		$data['start_time']			= time();
+		// 查询是不是有记录在使用中
+		$oldRecordId 				= $ExamRecord->query()->where([['custom_uid','=',$uid],['course_id','=',$data['course_id']],['status','=',0]])->value('id');
+        // 查询课程数据
+		$questionList				= $Model->getList($data['course_id']);
+		// 获取数据
+		foreach ($questionList as $key => $value) {
+			# 获取习题数据
+			$value['question_title']= (string) $VideoQuestion->getOne($value['question_id'],'title');
+			$value['answer_list'] 	= $VideoAnswer->getListByQuestion($value['question_id']);
+			$value['answer_list'] 	= array_values($value['answer_list']);
+			// 如果没有题目选项,删除
+			if( !$value['answer_list'] ){
+				// 如果没有题目选项,删除
+				unset($questionList[$key]);
+				continue;
+			}
+			// 重组
+			$questionList[$key]		= $value;
+		}
+		// 题目数量
+		$data['question_total']		= count($questionList);
+		// 新增/修改记录
+		$data['record_id']			= $oldRecordId ? $ExamRecord->edit($oldRecordId,$data) : $ExamRecord->add($data);
+		// 如果记录失败
+		if( !$data['record_id'] )	return json_send(['code'=>'error','msg'=>'获取详情失败,请重试']);
+		// 习题列表
+		$data['question_list']		= array_values($questionList);
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'获取成功','data'=>$data]);
+    }
+
+
+}

+ 158 - 0
app/Http/Controllers/Api/Video/ExamRecord.php

@@ -0,0 +1,158 @@
+<?php namespace App\Http\Controllers\Api\Video;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\Video\Answer as VideoAnswer;
+use App\Models\Video\Question as VideoQuestion;
+use App\Models\Video\ExamAnswer;
+use App\Models\Video\ExamRecord as Model;
+use App\Models\CustomScore;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 课后评测记录
+ *
+ * @author    刘相欣
+ *
+ */
+class ExamRecord extends Api{
+	
+    /**
+     * 交卷     /api/video_exam_record/hand_in
+     * 
+     */
+    public function hand_in(Model $Model,ExamAnswer $ExamAnswer,VideoQuestion $VideoQuestion,VideoAnswer $VideoAnswer,CustomScore $CustomScore){
+        // 用户登录
+        $uid                        	= $this->checkLogin();
+        // 接收参数
+        $id         					= request('record_id',0);
+		$answerList 					= request('answer_list',''); // 示例 '[{"question_id":43,"answer_id":128}]'
+		// 组合数据
+		$data['custom_uid']				= $uid;
+		$data['end_time']				= time();
+		$data['status']					= 1;
+		// 如果没有记录
+		if( !$id ) 						return json_send(['code'=>'error','msg'=>'请选择的记录ID']);
+		// 解析json结构
+		$answerList						= json_decode($answerList,true);
+		// 如果没有记录
+		if( !$answerList || !is_array($answerList) ) return json_send(['code'=>'error','msg'=>'请先答题']);
+		// 查询记录
+		$record							= $Model->query()->where([['id','=',$id]])->first();
+		// 如果没有记录
+		if( !$record ) 					return json_send(['code'=>'error','msg'=>'记录不存在!']);
+		// 转数据
+		$record							= $record->toArray();
+		// 如果没有记录
+		if( $record['status'] ) 		return json_send(['code'=>'error','msg'=>'请勿重复交卷']);
+		// 写入列表
+		$insertList						= [];
+		// 循环题目列表
+		foreach ( $answerList as $value ) {
+			// 临时存储
+			$temp						= ['record_id'=>$id,'course_id'=>$record['course_id'],'custom_uid'=>$uid,'question_id'=>$value['question_id'],'answer_id'=>$value['answer_id']];
+			// 获取答案
+			$temp['is_answer']          = (int) $VideoAnswer->getOne($value['question_id'],$value['answer_id'],'is_answer');
+			// 如果没的话,获取题目分数
+			$temp['score']				= (int) $VideoQuestion->getOne($value['question_id'],'score');
+			// 获取题目分数
+			$temp['get_score']          = 0;
+			// 如果答对的话
+			if( $temp['is_answer'] )	{
+				// 查询该用户该课程该题答题记录
+				$answerRecord			= $ExamAnswer->query()->where([['custom_uid','=',$uid],['course_id','=',$record['course_id']],['question_id','=',$value['question_id']]])->first();;
+				// 如果有的答题记录,不再给分,没有答过题则给分
+				if( !$answerRecord )	$temp['get_score'] = $temp['score'];
+			}
+			// 时间
+			$temp['insert_time']		= $data['end_time'];
+			$temp['update_time']		= $data['end_time'];
+			// 重组
+			$insertList[]				= $temp;
+		}
+		// 评测时长
+		$data['exam_time']				= $data['end_time'] - $record['start_time'];
+		// 查询答题数量
+        $data['course_id']  			= $record['course_id'];
+        // 查询答题数量
+        $data['answer_total']  			= count($insertList);
+		// 查询答对数量
+        $data['isanswer_total']			= array_sum(array_column($insertList,'is_answer'));
+        // 查询答题总积分
+        $data['get_score']     			= (int) array_sum(array_column($insertList,'get_score'));
+
+		// 开始事务
+        DB::beginTransaction();
+        // 保存答题记录
+        $result                 		= $ExamAnswer->insert($insertList);
+        // 答题记录保存失败
+        if ( !$result )     			{
+            // 回滚事务
+            DB::rollBack();
+            // 失败提醒
+            return              		json_send(['code'=>'error', 'msg'=>'答题记录失败,请重试']);
+        }
+        // 如果有获取积分
+        if ($data['get_score']) 		{
+            // 积分奖励
+            $result             		= $CustomScore->trade($uid,$id,$data['get_score'],10,2,'课后评测奖励');
+            // 积分奖励失败
+            if( isset($result['error']) ) {
+                // 回滚事务
+                DB::rollBack();
+                // 失败提醒
+                return          		json_send(['code'=>'error', 'msg'=>'积分下发失败,请重试','data'=>['error'=>$result['error']]]);
+            }
+        }
+        // 写入/修改学习记录
+        $result                 		= $Model->edit($id,$data);
+        // 写入失败
+        if( !$result )          		{
+            // 回滚事务
+            DB::rollBack();
+            // 失败提醒
+            return              		json_send(['code'=>'error', 'msg'=>'测评记录失败,请重试','data'=>['error'=>'测评记录写入失败']]);
+        }
+        // 提交事务
+        DB::commit();
+        // 成功提醒
+        return                  		json_send(['code'=>'success', 'msg'=>'提交成功','data'=>$data]);
+    }
+
+
+	/**
+	 * 获取评测报告				/api/video_exam_record/get_report
+	 * 
+	 */
+	public function get_report(Model $Model){
+		// 登录信息
+		$uid 					= $this->checkLogin();
+		// 接收参数
+		$id 					= request('record_id',0);
+		// 返回结果
+		$data					= $Model->query()->where([['id','=',$id]])->first();
+		// 错误提示
+		if(!$data) 				return json_send(['code'=>'error','msg'=>'记录不存在']);
+		// 成功下发
+		return 					json_send(['code'=>'success','msg'=>'获取成功','data'=>$data]);
+	}
+
+
+	/**
+	 * 获取已完成的报告			 /api/video_exam_record/get_report_last
+	 * 
+	 */
+	public function get_report_last(Model $Model){
+		// 登录信息
+		$uid 					= $this->checkLogin();
+		$courseId				= request('course_id',0);
+		// 返回结果
+		$data					= $Model->query()->where([['course_id','=',$courseId],['custom_uid','=',$uid],['status','=',1]])->orderByDesc('id')->first();
+		// 错误提示
+		if(!$data) 				return json_send(['code'=>'error','msg'=>'记录不存在']);
+		// 成功下发
+		return 					json_send(['code'=>'success','msg'=>'获取成功','data'=>$data]);
+	}
+
+
+
+}

+ 132 - 0
app/Http/Controllers/Api/Video/LearnAnswer.php

@@ -0,0 +1,132 @@
+<?php namespace App\Http\Controllers\Api\Video;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\Video\LearnAnswer as Model;
+use App\Models\Video\Answer as VideoAnswer;
+use App\Models\Video\Question as VideoQuestion;
+use App\Models\Video\LearnQuestion;
+use App\Models\Video\LearnRecord;
+use App\Models\CustomScore;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 课程
+ *
+ * @author    刘相欣
+ *
+ */
+class LearnAnswer extends Api{
+	
+    
+    /**
+     * 获取答题记录      /api/video_learn_answer/get_list
+     * 
+     */
+    public function get_list(Model $Model,VideoQuestion $VideoQuestion,VideoAnswer $VideoAnswer){
+        // 用户登录
+        $uid                        = $this->checkLogin();
+        // 接收参数
+        $recordId                   = request('record_id',0);
+        // 如果不是课中习题
+        if( !$recordId )            return json_send(['code'=>'error','msg'=>'请选择学习记录']);
+        // 查询答题记录
+        $answerList                 = $Model->query()
+                                    ->where([['custom_uid','=',$uid],['record_id','=',$recordId]])
+                                    ->select(['id','record_id','course_id','question_id','answer_id','is_answer','get_score'])
+                                    ->get()->toArray();
+        // 循环答题
+        foreach ($answerList as $key => $value) {
+            // 题目标题
+            $value['question_title']= $VideoQuestion->getOne($value['question_id'],'title');
+			$value['answer_list'] 	= $VideoAnswer->getListByQuestion($value['question_id']);
+			$value['answer_list'] 	= array_values($value['answer_list']);
+            // 重组
+			$answerList[$key]		= $value;
+        }
+        // 返回结果
+        return                      json_send(['code'=>'success','msg'=>'获取成功','data'=>$answerList]);
+    }
+
+    /**
+     * 上报课中习题答案     /api/video_learn_answer/play_exam
+     * 
+     */
+    public function play_exam(Model $Model,LearnQuestion $LearnQuestion,VideoQuestion $VideoQuestion,VideoAnswer $VideoAnswer,CustomScore $CustomScore,LearnRecord $LearnRecord){
+        // 用户登录
+        $uid                        = $this->checkLogin();
+        // 接收参数
+        $data['custom_uid']         = $uid;
+		$data['record_id']          = request('record_id',0);
+        $data['course_id']          = request('course_id',0);
+        $data['question_id']        = request('question_id',0);
+        $data['answer_id']          = request('answer_id',0);
+		// 
+		if( ! $data['record_id'] )	return json_send(['code'=>'error','msg'=>'请选择学习记录']);
+		if( ! $data['course_id'] )	return json_send(['code'=>'error','msg'=>'请选择学习课程']);
+		if( ! $data['question_id'] )return json_send(['code'=>'error','msg'=>'请选择习题问题']);
+		if( ! $data['answer_id'] )	return json_send(['code'=>'error','msg'=>'请选择习题答案']);
+		// 判断是不是课中习题
+        $isLearnQuestion            = $LearnQuestion->getOne($data['course_id'],$data['question_id']);
+        // 如果不是课中习题
+        if( !$isLearnQuestion )     return json_send(['code'=>'error','msg'=>'题目有误或者题目已停用']);
+
+        // 通过记录ID。查询问题是否已经回答
+		$havaAnswer					= $Model->query()->where([['record_id','=',$data['record_id']],['custom_uid','=',$uid],['question_id','=',$data['question_id']]])->first();
+		// 如果答过题
+		if( $havaAnswer )			return json_send(['code'=>'error','msg'=>'已答题,请无重复作答']);
+		// 查询该用户该课程该题答题记录
+        $answerRecord               = $Model->where([['custom_uid','=',$uid],['course_id','=',$data['course_id']],['question_id','=',$data['question_id']]])->first();
+        // 获取题目分数
+        $data['score']              = (int) $VideoQuestion->getOne($data['question_id'],'score');
+        // 获取答案
+        $data['is_answer']          = (int) $VideoAnswer->getOne($data['question_id'],$data['answer_id'],'is_answer');
+        // 如果没有答题记录,并且题目答案正确,则获取分数
+        $data['get_score']          = (!$answerRecord && $data['is_answer']) ? $data['score'] : 0;
+
+        // 获取题目数量
+        $learnData['question_total']= count($LearnQuestion->getList($data['course_id']));
+        // 查询答题数量
+        $learnData['answer_total']  = ($Model->query()->where([['record_id','=',$data['record_id']],['custom_uid','=',$uid]])->count()) + 1;
+		// 查询答对数量
+        $learnData['isanswer_total']= ($Model->query()->where([['record_id','=',$data['record_id']],['custom_uid','=',$uid],['is_answer','=',1]])->count()) + ($data['is_answer'] ? 1 : 0);
+        // 查询答题总积分
+        $learnData['get_score']     = intval($Model->query()->where([['record_id','=',$data['record_id']],['custom_uid','=',$uid]])->sum('get_score')) + $data['get_score'];
+
+        // 开始事务
+        DB::beginTransaction();
+        // 保存答题记录
+        $data['id']                 = $Model->add($data);
+        // 答题记录保存失败
+        if ( !$data['id'] )     {
+            // 回滚事务
+            DB::rollBack();
+            // 失败提醒
+            return              json_send(['code'=>'error', 'msg'=>'答题记录失败,请重试']);
+        }
+        // 如果有获取积分
+        if ($data['get_score']) {
+            // 积分奖励
+            $result             = $CustomScore->trade($uid,$data['id'],$data['get_score'],10,1,'课中评测奖励');
+            // 积分奖励失败
+            if( isset($result['error']) )      {
+                // 回滚事务
+                DB::rollBack();
+                // 失败提醒
+                return          json_send(['code'=>'error', 'msg'=>'积分下发失败,请重试','data'=>['error'=>$result['error']]]);
+            }
+        }
+        // 写入/修改学习记录
+        $result                 = $LearnRecord->edit($data['record_id'],$learnData);
+        // 写入失败
+        if( !$result )          {
+            // 回滚事务
+            DB::rollBack();
+            // 失败提醒
+            return              json_send(['code'=>'error', 'msg'=>'学习记录失败,请重试','data'=>['error'=>'学习记录写入失败']]);
+        }
+        // 提交事务
+        DB::commit();
+        // 成功提醒
+        return                  json_send(['code'=>'success', 'msg'=>'提交成功','data'=>$data]);
+    }
+}

+ 48 - 0
app/Http/Controllers/Api/Video/LearnQuestion.php

@@ -0,0 +1,48 @@
+<?php namespace App\Http\Controllers\Api\Video;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\Video\Answer as VideoAnswer;
+use App\Models\Video\Question as VideoQuestion;
+use App\Models\Video\LearnQuestion as Model;
+
+/**
+ * 课程
+ *
+ * @author    刘相欣
+ *
+ */
+class LearnQuestion extends Api{
+	
+    /**
+     * 获取习题列表      /api/video_learn_question/get_list
+     * 
+     */
+    public function get_list(Model $Model,VideoQuestion $VideoQuestion,VideoAnswer $VideoAnswer){
+        // 用户登录
+        $uid                        = $this->checkLogin();
+        // 接收参数
+        $courseId                   = request('course_id',0);
+        // 查询课程数据
+		$questionList				= $Model->query()->where([['course_id','=',$courseId],['status','=',0]])->orderBy('play_time')->select(['question_id','play_time'])->get()->toArray();
+		// 获取数据
+		foreach ($questionList as $key => $value) {
+			# 获取习题数据
+			$value['question_title']= $VideoQuestion->getOne($value['question_id'],'title');
+			$value['answer_list'] 	= $VideoAnswer->getListByQuestion($value['question_id']);
+			$value['answer_list'] 	= array_values($value['answer_list']);
+			// 如果没有题目选项,删除
+			if( !$value['answer_list'] ){
+				// 如果没有题目选项,删除
+				unset($questionList[$key]);
+				continue;
+			}
+			// 重组
+			$questionList[$key]		= $value;
+		}
+        // 习题列表
+		$questionList               = array_values($questionList);
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'暂无','data'=>$questionList]);
+    }
+
+}

+ 76 - 0
app/Http/Controllers/Api/Video/LearnRecord.php

@@ -0,0 +1,76 @@
+<?php namespace App\Http\Controllers\Api\Video;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\Video\LearnRecord as Model;
+use App\Models\Video\LearnQuestion;
+/**
+ * 学习记录
+ *
+ * @author    刘相欣
+ *
+ */
+class LearnRecord extends Api{
+	
+	/**
+	 * 新增学习记录	/api/video_learn_record/add
+	 * 
+	 */
+	public function add(Model $Model,LearnQuestion $LearnQuestion){
+		// 登录信息
+		$uid 					= $this->checkLogin();
+		// 接收参数
+		$data['custom_uid']		= $uid;
+		$data['course_id']		= request('course_id',0);
+		$data['video_inittime']	= request('video_inittime',0);
+		$data['video_lasttime']	= $data['video_inittime'];
+		$data['start_time']		= time();
+		$data['question_total']	= count($LearnQuestion->getList($data['course_id']));
+		// 查询播放记录
+		$data['id']				= $Model->add($data);
+		// 上报失败
+		if( !$data['id'] )		return json_send(['code'=>'error','msg'=>'创建成功']);
+		// 返回结果
+		return 					json_send(['code'=>'success','msg'=>'创建失败','data'=>$data]);
+	}
+
+
+	/**
+	 * 修改学习记录				/api/video_learn_record/update_playtime
+	 * 
+	 */
+	public function update_playtime(Model $Model){
+		// 登录信息
+		$uid 					= $this->checkLogin();
+		// 接收参数
+		$id						= request('record_id',0);
+		$data['video_lasttime']	= (int) ceil(request('video_playtime',0));
+		$data['status']			= request('status',0);
+		$data['end_time']		= time();
+		// 查询播放记录
+		$data['id']				= $Model->edit($id,$data);
+		// 上报失败
+		if( !$data['id'] )		return json_send(['code'=>'error','msg'=>'上报失败']);
+		// 返回结果
+		return 					json_send(['code'=>'success','msg'=>'上报成功','data'=>$data]);
+	}
+
+
+
+	/**
+	 * 获取学习报告				/api/video_learn_record/get_report
+	 * 
+	 */
+	public function get_report(Model $Model){
+		// 登录信息
+		$uid 					= $this->checkLogin();
+		// 接收参数
+		$id 					= request('record_id',0);
+		// 返回结果
+		$data					= $Model->query()->where([['id','=',$id]])->first();
+		// 错误提示
+		if(!$data) 				return json_send(['code'=>'error','msg'=>'记录不存在']);
+		// 成功下发
+		return 					json_send(['code'=>'success','msg'=>'获取成功','data'=>$data]);
+	}
+
+}

+ 49 - 0
app/Http/Requests/Admin/Video/Answer.php

@@ -0,0 +1,49 @@
+<?php namespace App\Http\Requests\Admin\Video;
+
+use App\Http\Requests\BaseRequest;
+
+/**
+ * 选项验证器
+ * 
+ */
+class Answer extends BaseRequest
+{
+    /**
+     * 获取应用于请求的规则
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        // 返回结果
+        return      [
+            // 有时候我们希望某个字段在第一次验证失败后就停止运行验证规则,只需要将 bail 添加到规则中:
+            // 验证字段,验证规则,提示信息
+            'question_id' 		=> 'required|integer|gt:0',
+	        'value' 			=> 'required',
+	        'id'                => 'required|integer|gt:0',
+        ];
+    }
+
+    // 场景列表
+    protected   $scenes         = [
+		'add'  		            => ['value','question_id'],
+        'edit'  		        => ['id','value','question_id'],
+        'set_answer'  		    => ['id'],
+	];
+
+    /**
+     * 获取已定义验证规则的错误消息
+     *
+     * @return array
+     */
+    public function messages()
+    {
+        return [
+            'id.required'       => 'ID未知',
+            'id.integer'        => 'ID格式错误',
+            'id.gt'   		    => 'ID格式错误',
+        ];
+    }
+    
+}

+ 55 - 0
app/Http/Requests/Admin/Video/Course.php

@@ -0,0 +1,55 @@
+<?php namespace App\Http\Requests\Admin\Video;
+
+use App\Http\Requests\BaseRequest;
+/**
+ * 验证器
+ * 
+ */
+class Course extends BaseRequest
+{
+    /**
+     * 获取应用于请求的规则
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        // 编辑时排除ID
+        // 返回结果
+        return      [
+            // 有时候我们希望某个字段在第一次验证失败后就停止运行验证规则,只需要将 bail 添加到规则中:
+            // 验证字段,验证规则,提示信息
+            'id'            => 'required|integer|gt:0',
+            'name'          => 'required|unique:video_course,name,'.request('id',0),
+            'status'        => 'required|integer|gte:0',
+            'video_src'     => 'required',
+        ];
+    }
+
+    // 场景列表
+    protected   $scenes         = [
+        'add'                   => ['name','video_src'],
+        'edit'                  => ['id','name','video_src'],
+        'set_status'            => ['id','status'],
+	];
+
+    /**
+     * 获取已定义验证规则的错误消息
+     *
+     * @return array
+     */
+    public function messages()
+    {
+        return [
+            'id.required'   		    => 'ID未知',
+            'id.integer'   		        => 'ID格式错误',
+            'id.gt'   		            => 'ID格式错误',
+            'name.required'   		    => '请输入课程名称',
+            'name.unique'   		    => '课程名称已存在',
+            'video_src.required'   		=> '请上传视频',
+            'status.integer'   		    => '状态格式错误',
+            'status.gte'   		        => '状态格式错误',
+        ];
+    }
+
+}

+ 53 - 0
app/Http/Requests/Admin/Video/CourseType.php

@@ -0,0 +1,53 @@
+<?php namespace App\Http\Requests\Admin\Video;
+
+use App\Http\Requests\BaseRequest;
+/**
+ * 验证器
+ * 
+ */
+class CourseType extends BaseRequest
+{
+    /**
+     * 获取应用于请求的规则
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        // 编辑时排除ID
+        // 返回结果
+        return      [
+            // 有时候我们希望某个字段在第一次验证失败后就停止运行验证规则,只需要将 bail 添加到规则中:
+            // 验证字段,验证规则,提示信息
+            'id'            => 'required|integer|gt:0',
+            'name'          => 'required|unique:video_course_type,name,'.request('id',0),
+            'status'        => 'required|integer|gte:0',
+        ];
+    }
+
+    // 场景列表
+    protected   $scenes         = [
+        'add'                   => ['name'],
+        'edit'                  => ['id','name'],
+        'set_status'            => ['id','status'],
+	];
+
+    /**
+     * 获取已定义验证规则的错误消息
+     *
+     * @return array
+     */
+    public function messages()
+    {
+        return [
+            'id.required'   		    => 'ID未知',
+            'id.integer'   		        => 'ID格式错误',
+            'id.gt'   		            => 'ID格式错误',
+            'name.required'   		    => '请输入类型名称',
+            'name.unique'   		    => '课程类型已存在',
+            'status.integer'   		    => '状态格式错误',
+            'status.gte'   		        => '状态格式错误',
+        ];
+    }
+
+}

+ 55 - 0
app/Http/Requests/Admin/Video/ExamQuestion.php

@@ -0,0 +1,55 @@
+<?php namespace App\Http\Requests\Admin\Video;
+
+use App\Http\Requests\BaseRequest;
+
+/**
+ * 验证器
+ * 
+ */
+class ExamQuestion extends BaseRequest
+{
+    /**
+     * 获取应用于请求的规则
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        // 返回结果
+        return      [
+            // 有时候我们希望某个字段在第一次验证失败后就停止运行验证规则,只需要将 bail 添加到规则中:
+            // 验证字段,验证规则,提示信息
+	        'question_id' 		=> 'required|integer|gt:0',
+            'course_id' 		=> 'required|integer|gt:0',
+	        'id'                => 'required|integer|gt:0',
+        ];
+    }
+
+    // 场景列表
+    protected   $scenes         = [
+		'add'  		            => ['question_id','course_id'],
+        'edit'  		        => ['id','question_id','course_id'],
+        'set_status'  		    => ['id'],
+	];
+
+    /**
+     * 获取已定义验证规则的错误消息
+     *
+     * @return array
+     */
+    public function messages()
+    {
+        return [
+            'id.required'               => 'ID未知',
+            'id.integer'                => 'ID格式错误',
+            'id.gt'   		            => 'ID格式错误',
+            'question_id.required'      => '请选择问题',
+            'question_id.integer'       => '问题ID格式错误',
+            'question_id.gt'   		    => '问题ID格式错误',
+            'course_id.required'        => '请选择课程',
+            'course_id.integer'         => '课程ID格式错误',
+            'course_id.gt'   		    => '课程ID格式错误',
+        ];
+    }
+    
+}

+ 55 - 0
app/Http/Requests/Admin/Video/LearnQuestion.php

@@ -0,0 +1,55 @@
+<?php namespace App\Http\Requests\Admin\Video;
+
+use App\Http\Requests\BaseRequest;
+
+/**
+ * 验证器
+ * 
+ */
+class LearnQuestion extends BaseRequest
+{
+    /**
+     * 获取应用于请求的规则
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        // 返回结果
+        return      [
+            // 有时候我们希望某个字段在第一次验证失败后就停止运行验证规则,只需要将 bail 添加到规则中:
+            // 验证字段,验证规则,提示信息
+	        'question_id' 		=> 'required|integer|gt:0',
+            'course_id' 		=> 'required|integer|gt:0',
+	        'id'                => 'required|integer|gt:0',
+        ];
+    }
+
+    // 场景列表
+    protected   $scenes         = [
+		'add'  		            => ['question_id','course_id'],
+        'edit'  		        => ['id','question_id','course_id'],
+        'set_status'  		    => ['id'],
+	];
+
+    /**
+     * 获取已定义验证规则的错误消息
+     *
+     * @return array
+     */
+    public function messages()
+    {
+        return [
+            'id.required'               => 'ID未知',
+            'id.integer'                => 'ID格式错误',
+            'id.gt'   		            => 'ID格式错误',
+            'question_id.required'      => '请选择问题',
+            'question_id.integer'       => '问题ID格式错误',
+            'question_id.gt'   		    => '问题ID格式错误',
+            'course_id.required'        => '请选择课程',
+            'course_id.integer'         => '课程ID格式错误',
+            'course_id.gt'   		    => '课程ID格式错误',
+        ];
+    }
+    
+}

+ 50 - 0
app/Http/Requests/Admin/Video/Question.php

@@ -0,0 +1,50 @@
+<?php namespace App\Http\Requests\Admin\Video;
+
+use App\Http\Requests\BaseRequest;
+
+/**
+ * 验证器
+ * 
+ */
+class Question extends BaseRequest
+{
+    /**
+     * 获取应用于请求的规则
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        // 返回结果
+        return      [
+            // 有时候我们希望某个字段在第一次验证失败后就停止运行验证规则,只需要将 bail 添加到规则中:
+            // 验证字段,验证规则,提示信息
+	        'title' 			=> 'required|unique:video_question,title,'.request('id',0),
+	        'id'                => 'required|integer|gt:0',
+        ];
+    }
+
+    // 场景列表
+    protected   $scenes         = [
+		'add'  		            => ['title'],
+        'edit'  		        => ['id','title'],
+        'set_status'  		    => ['id'],
+	];
+
+    /**
+     * 获取已定义验证规则的错误消息
+     *
+     * @return array
+     */
+    public function messages()
+    {
+        return [
+            'title.required'    => '题目必填',
+            'title.required'    => '题目已存在',
+            'id.required'       => 'ID未知',
+            'id.integer'        => 'ID格式错误',
+            'id.gt'   		    => 'ID格式错误',
+        ];
+    }
+    
+}

+ 6 - 0
app/Models/Traits/Score/BuyType.php

@@ -66,6 +66,12 @@ trait BuyType
                                         'name'          =>'拉新奖励',
                                         // 支付方式  方式名称
                                         'pay_type'      =>['1'=>['id'=>1,'name'=>'拉新奖励']],
+                                    ],'10'=>[
+                                        'id'            =>10,
+                                        // 类型名称
+                                        'name'          =>'课程测评',
+                                        // 支付方式  方式名称
+                                        'pay_type'      =>['1'=>['id'=>1,'name'=>'课中习题'],'2'=>['id'=>2,'name'=>'课后评测']],
                                     ]];
 
     /**

+ 123 - 0
app/Models/Video/Answer.php

@@ -0,0 +1,123 @@
+<?php namespace App\Models\Video;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 灯谜活动模型
+ * 
+ */
+class Answer extends Model
+{
+    use HasFactory;
+
+    // 与模型关联的表名
+    protected $table = 'video_answer';
+    // 是否主动维护时间戳
+    public $timestamps = false;
+    // 定义时间戳字段名
+    // const CREATED_AT = 'insert_time';
+    // const UPDATED_AT = 'update_time';
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function add($data)
+    {
+        // 时间
+        $data['insert_time']				= time();
+        $data['update_time']				= time();
+        // 写入数据表
+        $id						            = $this->query()->insertGetId($data);
+        // 如果操作失败
+        if( !$id )                          return $id;
+        // 更新缓存
+        if( isset($data['question_id']) )   $this->getList($data['question_id'],true);
+        // 返回结果
+        return                              $id;
+    }
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function edit($id,$data)
+    {
+        // 更新时间
+        $data['update_time']                = time();
+        // 写入数据表
+        $result						        = $this->query()->where(['id'=>$id])->update($data);
+        // 如果操作失败
+        if( !$result )                      return $result;
+        // 更新缓存
+        if( isset($data['question_id']) )   $this->getList($data['question_id'],true);
+        // 返回结果
+        return                              $result;
+    }
+
+    /**
+     * 获取列表
+     * @param   bool    $force  是否强制更新
+     * 
+     */
+    public function getList($questionId,$force = false)
+    {
+        // 结果数据
+        $list                  = $force ? [] : cache('admin:video:answer:list:'.$questionId);
+        // 不存在数据
+        if ( !$list ) {
+            // 从数据库获取数据
+            $data              = $this->query()->get(['id','question_id','value','is_answer'])->toArray();
+            // 循环处理数据
+            $list              = [];
+            // 进行更新
+            foreach ($data as $value) {
+                // 重组数据
+                $list[$value['question_id']][$value['id']] = $value;
+            }
+            // 存起来
+            cache(['admin:video:answer:list:'.$questionId=>$list]);
+        }
+        // 返回结果
+        return                  $list;
+    }
+
+
+    /**
+     * 获取配置平台对应的应用数据
+     * 
+     * @param   int     $questionId   问题ID
+     * @param   int     $id           ID
+     * @param   string  $field       字段名
+     * 
+     */
+    public function getListByQuestion($questionId)
+    {
+        // 获取列表数据
+        $list                   = $this->getList($questionId);
+        // 获取问题的列表
+        $list                   = isset($list[$questionId]) ? $list[$questionId] : [];
+        // 返回值
+        return                  $list;
+    }
+
+    /**
+     * 获取配置平台对应的应用数据
+     * 
+     * @param   int     $questionId   问题ID
+     * @param   int     $id           ID
+     * @param   string  $field       字段名
+     * 
+     */
+    public function getOne($questionId,$id,$field='')
+    {
+        // 获取列表数据
+        $list                   = $this->getListByQuestion($questionId);
+        // 获取数据
+        $one                    = isset($list[$id]) ? $list[$id] : [];
+        // 返回值
+        return                  empty($field) ? $one : ( isset($one[$field]) ? $one[$field] : null);
+    }
+
+}

+ 100 - 0
app/Models/Video/Course.php

@@ -0,0 +1,100 @@
+<?php namespace App\Models\Video;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 模型
+ * 
+ */
+class Course extends Model
+{
+    use HasFactory;
+
+    // 与模型关联的表名
+    protected $table = 'video_course';
+    // 是否主动维护时间戳
+    public $timestamps = false;
+    // 定义时间戳字段名
+    // const CREATED_AT = 'insert_time';
+    // const UPDATED_AT = 'update_time';
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function add($data)
+    {
+        // 时间
+        $data['insert_time']				= time();
+        $data['update_time']				= time();
+        // 写入数据表
+        $id						            = $this->query()->insertGetId($data);
+        // 更新缓存
+        $this->getList(true);
+        // 返回结果
+        return                              $id;
+    }
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function edit($id,$data)
+    {
+        // 更新时间
+        $data['update_time']                = time();
+        // 写入数据表
+        $result						        = $this->query()->where(['id'=>$id])->update($data);
+        // 更新缓存
+        $this->getList(true);
+        // 返回结果
+        return                              $result;
+    }
+
+    /**
+     * 获取列表
+     * @param   Bool    $force  是否强制更新
+     * 
+     */
+    public function getList($force = false)
+    {
+        // 结果数据
+        $list                  = $force ? [] : cache('admin:video:course:list');
+        // 不存在数据
+        if ( !$list ) {
+            // 从数据库获取数据
+            $data              = $this->query()->where([['status','=',0]])->get(['id','name','thumb','video_src','start_time','end_time'])->toArray();
+            // 循环处理数据
+            $list              = [];
+            // 进行更新
+            foreach ($data as $value) {
+                // 重组数据
+                $list[$value['id']] = $value;
+            }
+            // 存起来
+            cache(['admin:video:course:list'=>$list]);
+        }
+        // 返回结果
+        return                  $list;
+    }
+
+    /**
+     * 获取配置平台对应的应用数据
+     * 
+     * @param   Array      用户ID
+     * @param   String     指定字段
+     * 
+     */
+    public function getOne($id,$field='')
+    {
+        // 获取列表数据
+        $list                   = $this->getList();
+        dd($list);
+        // 获取数据
+        $one                    = isset($list[$id]) ? $list[$id] : [];
+        // 返回值
+        return                  empty($field) ? $one : ( isset($one[$field]) ? $one[$field] : null);
+    }
+
+}

+ 99 - 0
app/Models/Video/CourseType.php

@@ -0,0 +1,99 @@
+<?php namespace App\Models\Video;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 模型
+ * 
+ */
+class CourseType extends Model
+{
+    use HasFactory;
+
+    // 与模型关联的表名
+    protected $table = 'video_course_type';
+    // 是否主动维护时间戳
+    public $timestamps = false;
+    // 定义时间戳字段名
+    // const CREATED_AT = 'insert_time';
+    // const UPDATED_AT = 'update_time';
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function add($data)
+    {
+        // 时间
+        $data['insert_time']				= time();
+        $data['update_time']				= time();
+        // 写入数据表
+        $id						            = $this->query()->insertGetId($data);
+        // 更新缓存
+        $this->getList(true);
+        // 返回结果
+        return                              $id;
+    }
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function edit($id,$data)
+    {
+        // 更新时间
+        $data['update_time']                = time();
+        // 写入数据表
+        $result						        = $this->query()->where(['id'=>$id])->update($data);
+        // 更新缓存
+        $this->getList(true);
+        // 返回结果
+        return                              $result;
+    }
+
+    /**
+     * 获取列表
+     * @param   Bool    $force  是否强制更新
+     * 
+     */
+    public function getList($force = false)
+    {
+        // 结果数据
+        $list                  = $force ? [] : cache('admin:video:course:type:list');
+        // 不存在数据
+        if ( !$list ) {
+            // 从数据库获取数据
+            $data              = $this->query()->get(['id','status','name'])->toArray();
+            // 循环处理数据
+            $list              = [];
+            // 进行更新
+            foreach ($data as $value) {
+                // 重组数据
+                $list[$value['id']] = $value;
+            }
+            // 存起来
+            cache(['admin:video:course:type:list'=>$list]);
+        }
+        // 返回结果
+        return                  $list;
+    }
+
+    /**
+     * 获取配置平台对应的应用数据
+     * 
+     * @param   Array      用户ID
+     * @param   String     指定字段
+     * 
+     */
+    public function getOne($id,$field='')
+    {
+        // 获取列表数据
+        $list                   = $this->getList();
+        // 获取数据
+        $one                    = isset($list[$id]) ? $list[$id] : [];
+        // 返回值
+        return                  empty($field) ? $one : ( isset($one[$field]) ? $one[$field] : null);
+    }
+
+}

+ 53 - 0
app/Models/Video/ExamAnswer.php

@@ -0,0 +1,53 @@
+<?php namespace App\Models\Video;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 模型
+ * 
+ */
+class ExamAnswer extends Model
+{
+    use HasFactory;
+
+    // 与模型关联的表名
+    protected $table = 'video_exam_answer';
+    // 是否主动维护时间戳
+    public $timestamps = false;
+    // 定义时间戳字段名
+    // const CREATED_AT = 'insert_time';
+    // const UPDATED_AT = 'update_time';
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function add($data)
+    {
+        // 时间
+        $data['insert_time']				= time();
+        $data['update_time']				= time();
+        // 写入数据表
+        $id						            = $this->query()->insertGetId($data);
+        // 返回结果
+        return                              $id;
+    }
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function edit($id,$data)
+    {
+        // 更新时间
+        $data['update_time']                = time();
+        // 写入数据表
+        $result						        = $this->query()->where(['id'=>$id])->update($data);
+        // 返回结果
+        if( !$result )                      return 0;
+        // 返回结果
+        return                              $id;
+    }
+
+}

+ 84 - 0
app/Models/Video/ExamQuestion.php

@@ -0,0 +1,84 @@
+<?php namespace App\Models\Video;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 模型
+ * 
+ */
+class ExamQuestion extends Model
+{
+    use HasFactory;
+
+    // 与模型关联的表名
+    protected $table = 'video_exam_question';
+    // 是否主动维护时间戳
+    public $timestamps = false;
+    // 定义时间戳字段名
+    // const CREATED_AT = 'insert_time';
+    // const UPDATED_AT = 'update_time';
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function add($data)
+    {
+        // 时间
+        $data['insert_time']				= time();
+        $data['update_time']				= time();
+        // 写入数据表
+        $id						            = $this->query()->insertGetId($data);
+        // 如果操作失败
+        if( !$id )                          return $id;
+        // 更新缓存
+        if( isset($data['course_id']) )     $this->getList($data['course_id'],true);
+        // 返回结果
+        return                              $id;
+    }
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function edit($id,$data)
+    {
+        // 更新时间
+        $data['update_time']                = time();
+        // 写入数据表
+        $result						        = $this->query()->where(['id'=>$id])->update($data);
+        // 如果操作失败
+        if( !$result )                      return $result;
+        // 返回结果
+        return                              $result;
+    }
+
+    /**
+     * 获取列表
+     * @param   Bool    $force  是否强制更新
+     * 
+     */
+    public function getList($courseId,$force = false)
+    {
+        // 结果数据
+        $list                  = $force ? [] : cache('admin:video:exam:question:list:'.$courseId);
+        // 不存在数据
+        if ( !$list )          {
+            // 从数据库获取数据
+            $data              = $this->query()->where([['status','=',0],['course_id','=',$courseId]])->get(['id','course_id','question_id'])->toArray();
+            // 循环处理数据
+            $list              = [];
+            // 进行更新
+            foreach ($data as $value) {
+                // 重组数据
+                $list[$value['question_id']] = $value;
+            }
+            // 存起来
+            cache(['admin:video:exam:question:list:'.$courseId=>$list]);
+        }
+        // 返回结果
+        return                  $list;
+    }
+
+}

+ 53 - 0
app/Models/Video/ExamRecord.php

@@ -0,0 +1,53 @@
+<?php namespace App\Models\Video;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 模型
+ * 
+ */
+class ExamRecord extends Model
+{
+    use HasFactory;
+
+    // 与模型关联的表名
+    protected $table = 'video_exam_record';
+    // 是否主动维护时间戳
+    public $timestamps = false;
+    // 定义时间戳字段名
+    // const CREATED_AT = 'insert_time';
+    // const UPDATED_AT = 'update_time';
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function add($data)
+    {
+        // 时间
+        $data['insert_time']				= time();
+        $data['update_time']				= time();
+        // 写入数据表
+        $id						            = $this->query()->insertGetId($data);
+        // 返回结果
+        return                              $id;
+    }
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function edit($id,$data)
+    {
+        // 更新时间
+        $data['update_time']                = time();
+        // 写入数据表
+        $result						        = $this->query()->where(['id'=>$id])->update($data);
+        // 返回结果
+        if( !$result )                      return 0;
+        // 返回结果
+        return                              $id;
+    }
+
+}

+ 53 - 0
app/Models/Video/LearnAnswer.php

@@ -0,0 +1,53 @@
+<?php namespace App\Models\Video;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 模型
+ * 
+ */
+class LearnAnswer extends Model
+{
+    use HasFactory;
+
+    // 与模型关联的表名
+    protected $table = 'video_learn_answer';
+    // 是否主动维护时间戳
+    public $timestamps = false;
+    // 定义时间戳字段名
+    // const CREATED_AT = 'insert_time';
+    // const UPDATED_AT = 'update_time';
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function add($data)
+    {
+        // 时间
+        $data['insert_time']				= time();
+        $data['update_time']				= time();
+        // 写入数据表
+        $id						            = $this->query()->insertGetId($data);
+        // 返回结果
+        return                              $id;
+    }
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function edit($id,$data)
+    {
+        // 更新时间
+        $data['update_time']                = time();
+        // 写入数据表
+        $result						        = $this->query()->where(['id'=>$id])->update($data);
+        // 返回结果
+        if( !$result )                      return 0;
+        // 返回结果
+        return                              $id;
+    }
+
+}

+ 104 - 0
app/Models/Video/LearnQuestion.php

@@ -0,0 +1,104 @@
+<?php namespace App\Models\Video;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 模型
+ * 
+ */
+class LearnQuestion extends Model
+{
+    use HasFactory;
+
+    // 与模型关联的表名
+    protected $table = 'video_learn_question';
+    // 是否主动维护时间戳
+    public $timestamps = false;
+    // 定义时间戳字段名
+    // const CREATED_AT = 'insert_time';
+    // const UPDATED_AT = 'update_time';
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function add($data)
+    {
+        // 时间
+        $data['insert_time']				= time();
+        $data['update_time']				= time();
+        // 写入数据表
+        $id						            = $this->query()->insertGetId($data);
+        // 如果操作失败
+        if( !$id )                          return $id;
+        // 更新缓存
+        if( isset($data['course_id']) )     $this->getList($data['course_id'],true);
+        // 返回结果
+        return                              $id;
+    }
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function edit($id,$data)
+    {
+        // 更新时间
+        $data['update_time']                = time();
+        // 写入数据表
+        $result						        = $this->query()->where(['id'=>$id])->update($data);
+        // 如果操作失败
+        if( !$result )                      return $result;
+        // 更新缓存
+        if( isset($data['course_id']) )     $this->getList($data['course_id'],true);
+        // 返回结果
+        return                              $result;
+    }
+
+    /**
+     * 获取列表
+     * @param   Bool    $force  是否强制更新
+     * 
+     */
+    public function getList($courseId,$force = false)
+    {
+        // 结果数据
+        $list                  = $force ? [] : cache('admin:video:learn:question:list:'.$courseId);
+        // 不存在数据
+        if ( !$list )          {
+            // 从数据库获取数据
+            $data              = $this->query()->where([['status','=',0],['course_id','=',$courseId]])->get(['id','course_id','question_id','play_time'])->toArray();
+            // 循环处理数据
+            $list              = [];
+            // 进行更新
+            foreach ($data as $value) {
+                // 重组数据
+                $list[$value['question_id']] = $value;
+            }
+            // 存起来
+            cache(['admin:video:learn:question:list:'.$courseId=>$list]);
+        }
+        // 返回结果
+        return                  $list;
+    }
+
+    /**
+     * 获取配置平台对应的应用数据
+     * 
+     * @param   int     $courseId    课程ID
+     * @param   int     $questionId  问题ID
+     * @param   string  $field       字段名
+     * 
+     */
+    public function getOne($courseId,$questionId,$field='')
+    {
+        // 获取列表数据
+        $list                   = $this->getList($courseId);
+        // 获取数据
+        $one                    = isset($list[$questionId]) ? $list[$questionId] : [];
+        // 返回值
+        return                  empty($field) ? $one : ( isset($one[$field]) ? $one[$field] : null);
+    }
+
+}

+ 53 - 0
app/Models/Video/LearnRecord.php

@@ -0,0 +1,53 @@
+<?php namespace App\Models\Video;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 模型
+ * 
+ */
+class LearnRecord extends Model
+{
+    use HasFactory;
+
+    // 与模型关联的表名
+    protected $table = 'video_learn_record';
+    // 是否主动维护时间戳
+    public $timestamps = false;
+    // 定义时间戳字段名
+    // const CREATED_AT = 'insert_time';
+    // const UPDATED_AT = 'update_time';
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function add($data)
+    {
+        // 时间
+        $data['insert_time']				= time();
+        $data['update_time']				= time();
+        // 写入数据表
+        $id						            = $this->query()->insertGetId($data);
+        // 返回结果
+        return                              $id;
+    }
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function edit($id,$data)
+    {
+        // 更新时间
+        $data['update_time']                = time();
+        // 写入数据表
+        $result						        = $this->query()->where(['id'=>$id])->update($data);
+        // 返回结果
+        if( !$result )                      return 0;
+        // 返回结果
+        return                              $id;
+    }
+
+}

+ 103 - 0
app/Models/Video/Question.php

@@ -0,0 +1,103 @@
+<?php namespace App\Models\Video;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 模型
+ * 
+ */
+class Question extends Model
+{
+    use HasFactory;
+
+    // 与模型关联的表名
+    protected $table = 'video_question';
+    // 是否主动维护时间戳
+    public $timestamps = false;
+    // 定义时间戳字段名
+    // const CREATED_AT = 'insert_time';
+    // const UPDATED_AT = 'update_time';
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function add($data)
+    {
+        // 时间
+        $data['insert_time']				= time();
+        $data['update_time']				= time();
+        // 写入数据表
+        $id						            = $this->query()->insertGetId($data);
+        // 如果操作失败
+        if( !$id )                          return $id;
+        // 更新缓存
+        $this->getList(true);
+        // 返回结果
+        return                              $id;
+    }
+
+    /**
+     * 添加数据
+     * 
+     */
+    public function edit($id,$data)
+    {
+        // 更新时间
+        $data['update_time']                = time();
+        // 写入数据表
+        $result						        = $this->query()->where(['id'=>$id])->update($data);
+        // 如果操作失败
+        if( !$result )                      return $result;
+        // 更新缓存
+        $this->getList(true);
+        // 返回结果
+        return                              $result;
+    }
+
+    /**
+     * 获取列表
+     * @param   Bool    $force  是否强制更新
+     * 
+     */
+    public function getList($force = false)
+    {
+        // 结果数据
+        $list                  = $force ? [] : cache('admin:video:question:list');
+        // 不存在数据
+        if ( !$list ) {
+            // 从数据库获取数据
+            $data              = $this->query()->where([['status','=',0]])->get(['id','title','score'])->toArray();
+            // 循环处理数据
+            $list              = [];
+            // 进行更新
+            foreach ($data as $value) {
+                // 重组数据
+                $list[$value['id']] = $value;
+            }
+            // 存起来
+            cache(['admin:video:question:list'=>$list]);
+        }
+        // 返回结果
+        return                  $list;
+    }
+
+    /**
+     * 获取配置平台对应的应用数据
+     * 
+     * @param   Array      用户ID
+     * @param   String     指定字段
+     * 
+     */
+    public function getOne($id,$field='')
+    {
+        // 获取列表数据
+        $list                   = $this->getList();
+        // 获取数据
+        $one                    = isset($list[$id]) ? $list[$id] : [];
+        // 返回值
+        return                  empty($field) ? $one : ( isset($one[$field]) ? $one[$field] : null);
+    }
+
+}

+ 55 - 0
app/Servers/Aliyun/Oss.php

@@ -0,0 +1,55 @@
+<?php
+
+namespace App\Servers\Aliyun;
+
+use OSS\OssClient;
+use OSS\Core\OssException;
+use App\Facades\Servers\Logs\Log;
+use OSS\Credentials\StaticCredentialsProvider;
+
+/**
+ * 阿里oss
+ *
+ * @author    jun
+ */
+
+class Oss {
+
+    private \OSS\OssClient $ossClient;
+
+    function __construct()
+    {
+        $accessKeyId        =   config('aliyun.accessKeyId','');
+        $accessKeySecret    =   config('aliyun.accessKeySecret','');
+        $provider           =   new StaticCredentialsProvider($accessKeyId,$accessKeySecret);
+        $endpoint           =   "https://oss-cn-shenzhen.aliyuncs.com";
+        $config = array(
+            "provider" => $provider,
+            "endpoint" => $endpoint,
+            "signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
+            "region"=> "cn-shenzhen"
+        );
+        $this->ossClient    = new OssClient($config);
+    }
+    /**
+     *  使用签名URL上传
+     * @param string 	bucket	存储空间名称
+     * @param string 	object	不包含Bucket名称在内的Object完整路径
+     *
+     * */
+    function signUrl($bucket, $object, $options=['Content-Type'=>'multipart/form-data'] )
+    {
+        // 指定签名URL的过期时间为600s(最长可达32400s)。
+        $timeout = 600;
+        try {
+            // 生成签名URL。
+            $signedUrl = $this->ossClient->signUrl($bucket, $object, $timeout, "PUT",$options);
+            // 返回结果
+            return $signedUrl;
+        } catch (OssException $e) {
+            Log::error('oss/signUrl','获取签名URL上传失败,错误:'.json_encode($e->getMessage()));
+            return ['error'=>$e->getMessage()];
+        }
+    }
+    
+}

+ 1 - 0
composer.json

@@ -7,6 +7,7 @@
     "require": {
         "php": "^7.3|^8.0",
         "alibabacloud/dysmsapi-20170525": "3.1.1",
+        "aliyuncs/oss-sdk-php": "^2.7",
         "fideloper/proxy": "^4.4",
         "firebase/php-jwt": "^6.10",
         "fruitcake/laravel-cors": "^2.0",

+ 55 - 4
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "5b9b61d91311f39b4ffa1e237fa52a1e",
+    "content-hash": "0dd729ca9353270648f6cb5292e5d3b2",
     "packages": [
         {
             "name": "adbario/php-dot-notation",
@@ -504,6 +504,57 @@
             },
             "time": "2022-08-02T04:12:58+00:00"
         },
+        {
+            "name": "aliyuncs/oss-sdk-php",
+            "version": "v2.7.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/aliyun/aliyun-oss-php-sdk.git",
+                "reference": "483dd0b8bff5d47f0e4ffc99f6077a295c5ccbb5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/aliyun/aliyun-oss-php-sdk/zipball/483dd0b8bff5d47f0e4ffc99f6077a295c5ccbb5",
+                "reference": "483dd0b8bff5d47f0e4ffc99f6077a295c5ccbb5",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "php": ">=5.3"
+            },
+            "require-dev": {
+                "php-coveralls/php-coveralls": "*",
+                "phpunit/phpunit": "*"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "OSS\\": "src/OSS"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Aliyuncs",
+                    "homepage": "http://www.aliyun.com"
+                }
+            ],
+            "description": "Aliyun OSS SDK for PHP",
+            "homepage": "http://www.aliyun.com/product/oss/",
+            "support": {
+                "issues": "https://github.com/aliyun/aliyun-oss-php-sdk/issues",
+                "source": "https://github.com/aliyun/aliyun-oss-php-sdk/tree/v2.7.2"
+            },
+            "time": "2024-10-28T10:41:12+00:00"
+        },
         {
             "name": "asm89/stack-cors",
             "version": "v2.1.1",
@@ -11035,12 +11086,12 @@
     ],
     "aliases": [],
     "minimum-stability": "dev",
-    "stability-flags": [],
+    "stability-flags": {},
     "prefer-stable": true,
     "prefer-lowest": false,
     "platform": {
         "php": "^7.3|^8.0"
     },
-    "platform-dev": [],
-    "plugin-api-version": "2.3.0"
+    "platform-dev": {},
+    "plugin-api-version": "2.6.0"
 }

+ 24 - 0
resources/views/admin/video_answer/add.blade.php

@@ -0,0 +1,24 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<form class="post-form" action="" method="post">
+	<div class="form-group col-sm-12">
+		<label class="control-label">题目标题</label>
+		<select class="form-control selectpicker" name="question_id"  data-live-search="true" data-live-search-placeholder="搜索题目" data-none-results-text="未搜索到 {0}" title="选择题目">
+			@foreach ($questionList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == request('question_id',0) ) selected="" @endif >{{$value['title']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-12">
+		<label class="control-label">题目选项</label>
+		<input class="form-control" required="required" type="text" placeholder="题目选项" name="value" maxlength="255" value="" />
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection

+ 25 - 0
resources/views/admin/video_answer/edit.blade.php

@@ -0,0 +1,25 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<form class="post-form" action="" method="post">
+	<div class="form-group col-sm-12">
+		<label class="control-label">题目标题</label>
+		<select class="form-control selectpicker" name="question_id"  data-live-search="true" data-live-search-placeholder="搜索题目" data-none-results-text="未搜索到 {0}" title="选择题目">
+			@foreach ($questionList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == $oldData['question_id'] ) selected="" @endif >{{$value['title']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-12">
+		<label class="control-label">题目选项</label>
+		<input class="form-control" required="required" type="text" placeholder="题目选项" name="value" maxlength="255" value="{{$oldData['value']}}" />
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input type="hidden" name="id" id="id" value="{{$oldData['id']}}" />
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection

+ 84 - 0
resources/views/admin/video_answer/index.blade.php

@@ -0,0 +1,84 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+
+@if(check_auth('admin/video_answer/add'))
+	<div class="page-header">
+		<a href="{{url('admin/video_answer/add?'.http_build_query(['question_id'=>request('question_id',0)]))}}" class="btn btn-primary">新增</a>
+	</div>
+@endif
+
+<form action="" method="get" class="form-horizontal form-line">
+	<div class="form-group col col-lg-8 col-md-12 col-sm-12 col-xs-12" style="margin-right: 2px;">
+		<select name="question_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索题目" data-none-results-text="未搜索到 {0}" title="选择题目">
+			@foreach ($questionList as $value)
+				<option value="{{$value['id']}}"  @if( $value['id'] == request('question_id',0) ) selected="" @endif >{{$value['title']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<input type="submit" class="btn btn-sm btn-primary" value="查询"/>
+	<a href="{{url('admin/video_answer/index')}}" class="btn btn-sm btn-default" >重置</a>
+</form>
+
+<div class="row">
+	<div class="col-xs-12">	
+		<div class="table-responsive">
+			<table class="table table-striped table-bordered table-hover">
+				<thead>
+					<tr>
+						<th>ID</th>
+						<th>题目</th>
+						<th>题目选项</th>
+						<th>是否答案</th>
+						<th>修改时间</th>
+						<th>操作</th>									
+					</tr>
+				</thead>
+				
+				<tbody>
+						@foreach ($list as $a)
+						<tr>
+							<th>{{$a['id']}}</th>
+							<td>
+							@foreach ($questionList as $value)
+								@if( $value['id'] == $a['question_id'] )
+								{{$value['title']}}								
+								@endif
+							@endforeach
+							</td>
+							<td>{{$a['value']}}</td>
+							<td>
+								@if( $a['is_answer'] )
+								是
+								@else
+								否
+								@endif
+							</td>
+							<td> {{date('Y/m/d H:i:s',$a['update_time'])}}</td>
+							<td>
+								@if(check_auth('admin/video_answer/edit'))
+								<a href="{{url('admin/video_answer/edit?'.http_build_query(['id'=>$a['id']]))}}" class="btn btn-sm btn-warning" >编辑</a>
+								@endif
+								@if(check_auth('admin/video_answer/set_answer'))
+									@if( !$a['is_answer'] )
+									<a data-url="{{url('admin/video_answer/set_answer?'.http_build_query(['id'=>$a['id'],'is_answer'=>1]))}}" class="set_status btn btn-sm btn-danger" >设为答案</a>
+									@endif
+								@endif
+							</td>							
+						</tr>  
+						@endforeach
+						<tr>
+							<td colspan="20" class="page">{{$list->render()}}</td>
+						</tr>
+						<tr>
+							<td colspan="20">总计 {{$list->total()}} 个题目</td>
+						</tr>
+				</tbody>
+				
+			</table>
+		</div>
+	</div>
+</div>
+@endsection

+ 127 - 0
resources/views/admin/video_course/add.blade.php

@@ -0,0 +1,127 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<form class="post-form" action="" method="post">
+	<div class="form-group col-sm-2">
+		<label class="control-label">课程配图</label>
+		<div id="thumb">
+			<a id="thumb-image" href="#" data-toggle="image" class="img-thumb">
+				<img src="{{path_compat('')}}" height="100" />
+			</a>
+			<input type="hidden" name="thumb" value="" id="input-image" />
+		</div>
+	</div>
+	<div class="form-group col-sm-2">
+		<label class="control-label">课程视频</label>
+		<div id="video_src">
+			<a id="video_upload" href="javascript:;" class="img-thumb" >
+				<video src="{{path_compat('')}}" poster="{{path_compat('')}}" height="100" width="100" ></video>
+			</a>
+			<input type="hidden" name="video_src" value=""  />
+		</div>
+	</div>
+	<div class="form-group col-sm-2">
+		<label class="control-label">课程名称</label>
+		<input class="form-control" required="required" type="text" placeholder="课程名称" maxlength="40" name="name" value="" />
+	</div>
+	<div class="form-group col-sm-2">
+		<label class="control-label">课程类型</label>
+		<select class="form-control" name="type_id" required="required">
+			@foreach ($typeList as $value)
+				<option value="{{$value['id']}}"  >{{$value['name']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-2">
+		<label class="control-label">开始时间</label>
+		<input class="form-control" required="required" type="datetime-local" placeholder="开始时间"  name="start_time" value="" />
+	</div>
+	<div class="form-group col-sm-2">
+		<label class="control-label">结束时间</label>
+		<input class="form-control" required="required" type="datetime-local" placeholder="结束时间" name="end_time" value="" />
+	</div>
+	<div class="form-group col-sm-12">
+		<label class="control-label">课程介绍</label>
+		<textarea required="required" id="container" name="content" placeholder="课程介绍" ></textarea>
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection
+@section('javascript')
+<script src="/static/ueditor/ueditor.config.js"></script>  
+<script src="/static/ueditor/ueditor.all.js"></script>
+<script type="text/javascript">
+	var editor = new UE.ui.Editor();
+	editor.render("container");
+</script>
+<script type="text/javascript">
+	$('#video_upload').on('click', function() {
+		// 定义预签名URL
+		var signedUrl	= '';
+		var videoSrc	= '';
+		// 请求接口获取签名URL
+		$.ajax({
+			url: "{{url('admin/video_course/get_sign_url')}}",
+			type: 'get',
+			dataType: 'json',
+			success: function(data) {
+				// 判断返回值
+				if(data.code != 'success'){
+					art.dialog({content: data.msg,lock: true,ok: function() {}});
+					return ;
+				}
+				// 获取签名URL
+				signedUrl = data.data.sign_url;
+				videoSrc  = data.data.video_src;
+				// 没有获取到结果的话,结束
+				if( !signedUrl ) {
+					return;
+				}
+				// 移除之前上传的表单
+				$('#form-upload').remove();
+				// 生成一个表单,并且使用CSRF
+				$('body').prepend('<form enctype="multipart/form-data" id="form-upload" style="display: none;"><input osctype="btn_upload_file" id="form-upload-file" type="file" name="file" /> @csrf </form>');
+				$('#form-upload input[name=\'file\']').trigger('click');
+			},
+			error: function(xhr, status, error) {
+				console.error('Error:', error);
+			}
+		});
+		
+		$(document).on('change','#form-upload-file',function(){
+			// 获取文件
+			const fileInput = document.getElementById('form-upload-file');
+			const file = fileInput.files[0];
+			// 如果没有上传文件
+			if ( !file ) {
+				art.dialog({content: '请上传文件',lock: true,ok: function() {}});
+				return ;
+			}
+			// 调用上传
+			upload(file, signedUrl);
+		})
+
+		const upload = async (file, presignedUrl) => {
+			// 提示上传中
+			art.dialog({id:'loading',lock: true,title:'视频上传中'});
+			// 上传文件
+			const response = await fetch(presignedUrl, {method: 'PUT',body: file.slice(0, file.size)});
+			// 移除loading
+			art.dialog.list['loading'].close();
+			// 结果
+			if (!response.ok) {
+				art.dialog({content: '上传失败',lock: true,ok: function() {}});
+				return ;
+			}
+			// 显示上传成功的图片
+			$('#video_upload').html('<video src="'+videoSrc+'" height="100" width="100" ></video>');
+			$('#video_src input').val(videoSrc);
+		};
+	});
+</script>
+@endsection

+ 128 - 0
resources/views/admin/video_course/edit.blade.php

@@ -0,0 +1,128 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<form class="post-form" action="" method="post">
+	<div class="form-group col-sm-2">
+		<label class="control-label">课程配图</label>
+		<div id="thumb">
+			<a id="thumb-image" href="#" data-toggle="image" class="img-thumb">
+				<img src="{{path_compat($oldData['thumb'])}}" height="100" />
+			</a>
+			<input type="hidden" name="thumb" value="{{$oldData['thumb']}}" id="input-image" />
+		</div>
+	</div>
+	<div class="form-group col-sm-2">
+		<label class="control-label">课程视频</label>
+		<div id="video_src">
+			<a id="video_upload" href="javascript:;" class="img-thumb" >
+				<video src="{{$oldData['video_src']}}" height="100" width="100" ></video>
+			</a>
+			<input type="hidden" name="video_src" value="{{$oldData['video_src']}}"  />
+		</div>
+	</div>
+	<div class="form-group col-sm-2">
+		<label class="control-label">课程名称</label>
+		<input class="form-control" required="required" type="text" placeholder="课程名称" maxlength="40" name="name" value="{{$oldData['name']}}" />
+	</div>
+	<div class="form-group col-sm-2">
+		<label class="control-label">课程类型</label>
+		<select class="form-control" name="type_id" required="required">
+			@foreach ($typeList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == $oldData['type_id'])  selected @endif >{{$value['name']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-2">
+		<label class="control-label">开始时间</label>
+		<input class="form-control" required="required" type="datetime-local" placeholder="开始时间"  name="start_time" value="{{date('Y-m-d H:i',$oldData['start_time'])}}" />
+	</div>
+	<div class="form-group col-sm-2">
+		<label class="control-label">结束时间</label>
+		<input class="form-control" required="required" type="datetime-local" placeholder="结束时间" name="end_time" value="{{date('Y-m-d H:i',$oldData['end_time'])}}" />
+	</div>
+	<div class="form-group col-sm-12">
+		<label class="control-label">课程内容</label>
+		<textarea required="required" id="container" name="content" placeholder="课程内容" >{{$oldData['content']}}</textarea>
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input type="hidden" name="id" value="{{$oldData['id']}}" />
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection
+@section('javascript')
+<script src="/static/ueditor/ueditor.config.js"></script>  
+<script src="/static/ueditor/ueditor.all.js"></script>
+<script type="text/javascript">
+	var editor = new UE.ui.Editor();
+	editor.render("container");
+</script>
+<script type="text/javascript">
+	$('#video_upload').on('click', function() {
+		// 定义预签名URL
+		var signedUrl	= '';
+		var videoSrc	= '';
+		// 请求接口获取签名URL
+		$.ajax({
+			url: "{{url('admin/video_course/get_sign_url')}}",
+			type: 'get',
+			dataType: 'json',
+			success: function(data) {
+				// 判断返回值
+				if(data.code != 'success'){
+					art.dialog({content: data.msg,lock: true,ok: function() {}});
+					return ;
+				}
+				// 获取签名URL
+				signedUrl = data.data.sign_url;
+				videoSrc  = data.data.video_src;
+				// 没有获取到结果的话,结束
+				if( !signedUrl ) {
+					return;
+				}
+				// 移除之前上传的表单
+				$('#form-upload').remove();
+				// 生成一个表单,并且使用CSRF
+				$('body').prepend('<form enctype="multipart/form-data" id="form-upload" style="display: none;"><input osctype="btn_upload_file" id="form-upload-file" type="file" name="file" /> @csrf </form>');
+				$('#form-upload input[name=\'file\']').trigger('click');
+			},
+			error: function(xhr, status, error) {
+				console.error('Error:', error);
+			}
+		});
+		
+		$(document).on('change','#form-upload-file',function(){
+			// 获取文件
+			const fileInput = document.getElementById('form-upload-file');
+			const file = fileInput.files[0];
+			// 如果没有上传文件
+			if ( !file ) {
+				art.dialog({content: '请上传文件',lock: true,ok: function() {}});
+				return ;
+			}
+			// 调用上传
+			upload(file, signedUrl);
+		})
+
+		const upload = async (file, presignedUrl) => {
+			// 提示上传中
+			art.dialog({id:'loading',lock: true,title:'视频上传中'});
+			// 上传文件
+			const response = await fetch(presignedUrl, {method: 'PUT',body: file.slice(0, file.size)});
+			// 移除loading
+			art.dialog.list['loading'].close();
+			// 结果
+			if (!response.ok) {
+				art.dialog({content: '上传失败',lock: true,ok: function() {}});
+				return ;
+			}
+			// 显示上传成功的图片
+			$('#video_upload').html('<video src="'+videoSrc+'" height="100" width="100" ></video>');
+			$('#video_src input').val(videoSrc);
+		};
+	});
+</script>
+@endsection

+ 125 - 0
resources/views/admin/video_course/index.blade.php

@@ -0,0 +1,125 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<div class="page-header">
+	@if( check_auth('admin/video_course/add') )
+	<a href="{{url('admin/video_course/add')}}" class="btn btn-primary">新增</a>
+	@endif
+</div>
+<form action="" method="get" class="form-horizontal form-line">
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-12" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="name" value="{{request('name','')}}" placeholder="请输入课程标题查询" />
+	</div>
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-12" style="margin-right: 2px;">
+		<select class="form-control" name="type_id" >
+			<option value="0" >课程类型</option>
+			@foreach ($typeList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == request('type_id','') )  selected @endif >{{$value['name']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-12" style="margin-right: 2px;">
+		<select class="form-control" name="status" >
+			<option value="" >课程状态</option>
+			<option value="0" @if( !is_null(request('status')) && request('status',0) == 0 )  selected @endif >启用</option>
+			<option value="1" @if( !is_null(request('status')) && request('status',0) == 1 )  selected @endif >停用</option>
+		</select>
+	</div>
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-12" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="start_time" value="{{request('start_time','')}}" placeholder="请输入开始时间查询" />
+	</div>
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-12" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="end_time" value="{{request('end_time','')}}" placeholder="请输入结束时间查询" />
+	</div>
+	<input type="submit" class="btn btn-sm btn-primary" value="查询"/>
+	<a href="{{url('admin/video_course/index')}}" class="btn btn-sm btn-default" >重置</a>
+	@csrf
+</form>
+<div class="row">
+	<div class="col-xs-12">
+		<div class="table-responsive">
+			<table class="table table-striped table-bordered table-hover">
+				<thead>
+					<tr>
+						<th>ID</th>
+						<th>课程名称</th>
+						<th>课中习题</th>
+						<th>课后习题</th>
+						<th>课程有效期</th>
+						<th>课程状态</th>
+						<th>课程类型</th>
+						<th>修改时间</th>
+						<th>操作</th>
+					</tr>
+				</thead>
+				<tbody>
+					@foreach ($list as $a)
+					<tr>
+						<td> {{$a['id']}}</td>
+						<td> {{$a['name']}}</td>
+						<td> 
+							@if( check_auth('admin/video_learn_question/index') )
+							<a href="{{url('admin/video_learn_question/index?'.http_build_query(['course_id'=>$a['id']]))}}" title="课中习题">
+								课中习题
+							</a>
+							@endif
+						</td>
+						<td> 
+							@if( check_auth('admin/video_exam_question/index') )
+							<a href="{{url('admin/video_exam_question/index?'.http_build_query(['course_id'=>$a['id']]))}}" title="课后习题">
+								课后习题
+							</a>
+							@endif
+						</td>
+						<td> 
+							<p>开始:{{date('Y/m/d H:i',$a['start_time'])}} </p>
+							<p>结束: {{date('Y/m/d H:i',$a['end_time'])}} </p>
+						</td>
+						<td> @if ($a['status'] == 0) 启用 @endif @if ($a['status'] == 1) 停用 @endif</td>
+						<td> {{$a['type_name']}}</td>
+						<td> {{date('Y/m/d H:i',$a['update_time'])}}</td>
+						<td>
+							@if( check_auth('admin/video_course/edit') )
+							<a class="btn btn-sm btn-primary" href="{{url('admin/video_learn_record/index?'.http_build_query(['course_id'=>$a['id']]))}}" title="学习记录">
+								学习记录
+							</a>
+							@endif
+							@if( check_auth('admin/video_course/edit') )
+							<a class="btn btn-sm btn-primary" href="{{url('admin/video_exam_record/index?'.http_build_query(['course_id'=>$a['id']]))}}" title="课后评测记录">
+								课后评测记录
+							</a>
+							@endif
+							@if( check_auth('admin/video_course/edit') )
+							<a class="btn btn-sm btn-warning" href="{{url('admin/video_course/edit?'.http_build_query(['id'=>$a['id']]))}}" title="查看">
+								修改
+							</a>
+							@endif
+							@if( check_auth('admin/video_course/set_status') )
+								@if ( $a['status'] )
+									<a class="delete btn btn-sm btn-success" data-url="{{url('admin/video_course/set_status?'.http_build_query(['id'=>$a['id'],'status'=>'0']))}}">
+										启用
+									</a>
+								@else
+									<a class="delete btn btn-sm btn-danger" data-url="{{url('admin/video_course/set_status?'.http_build_query(['id'=>$a['id'],'status'=>'1']))}}">
+										停用
+									</a>
+								@endif
+							@endif
+						</td>
+					</tr>
+					@endforeach
+					<tr>
+						<td colspan="20" class="page">{{$list->render()}}</td>
+					</tr>
+					<tr>
+						<td colspan="20">总计 {{$list->total()}} 个课程</td>
+					</tr>
+				</tbody>
+
+			</table>
+		</div>
+	</div>
+</div>
+@endsection

+ 16 - 0
resources/views/admin/video_course_type/add.blade.php

@@ -0,0 +1,16 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<form class="post-form" action="" method="post">
+	<div class="form-group col-sm-4">
+		<label class="control-label">类型名称</label>
+		<input class="form-control" required="required" type="text" placeholder="类型名称" maxlength="10" name="name" value="" />
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection

+ 17 - 0
resources/views/admin/video_course_type/edit.blade.php

@@ -0,0 +1,17 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;" 
+@endsection
+@section('content')
+<form class="post-form" action="" method="post">
+	<div class="form-group col-sm-4">
+		<label class="control-label">类型名称</label>
+		<input class="form-control" required="required" type="text" placeholder="类型名称" maxlength="10" name="name" value="{{$oldData['name']}}" />
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input type="hidden" name="id" value="{{$oldData['id']}}" />
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection

+ 71 - 0
resources/views/admin/video_course_type/index.blade.php

@@ -0,0 +1,71 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<div class="page-header">
+	@if( check_auth('admin/video_course_type/add') )
+	<a href="{{url('admin/video_course_type/add')}}" class="btn btn-primary">新增</a>
+	@endif
+</div>
+<form action="" method="get" class="form-horizontal form-line">
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-12" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="name" value="{{request('name','')}}" placeholder="请输入类型名称查询" />
+	</div>
+	<input type="submit" class="btn btn-sm btn-primary" value="查询"/>
+	<a href="{{url('admin/video_course_type/index')}}" class="btn btn-sm btn-default" >重置</a>
+	@csrf
+</form>
+<div class="row">
+	<div class="col-xs-12">
+		<div class="table-responsive">
+			<table class="table table-striped table-bordered table-hover">
+				<thead>
+					<tr>
+						<th>ID</th>
+						<th>类型名称</th>
+						<th>类型状态</th>
+						<th>修改时间</th>
+						<th>操作</th>
+					</tr>
+				</thead>
+				<tbody>
+					@foreach ($list as $a)
+					<tr>
+						<td> {{$a['id']}}</td>
+						<td> {{$a['name']}}</td>
+						<td> @if ($a['status'] == 0) 启用 @endif @if ($a['status'] == 1) 停用 @endif</td>
+						<td> {{date('Y/m/d H:i',$a['update_time'])}}</td>
+						<td>
+							@if( check_auth('admin/video_course_type/edit') )
+							<a class="btn btn-sm btn-warning" href="{{url('admin/video_course_type/edit?'.http_build_query(['id'=>$a['id']]))}}" title="查看">
+								修改
+							</a>
+							@endif
+							@if( check_auth('admin/video_course_type/set_status') )
+								@if ( $a['status'] )
+									<a class="delete btn btn-sm btn-success" data-url="{{url('admin/video_course_type/set_status?'.http_build_query(['id'=>$a['id'],'status'=>'0']))}}">
+										启用
+									</a>
+								@else
+									<a class="delete btn btn-sm btn-danger" data-url="{{url('admin/video_course_type/set_status?'.http_build_query(['id'=>$a['id'],'status'=>'1']))}}">
+										停用
+									</a>
+								@endif
+							@endif
+						</td>
+					</tr>
+					@endforeach
+					<tr>
+						<td colspan="20" class="page">{{$list->render()}}</td>
+					</tr>
+					<tr>
+						<td colspan="20">总计 {{$list->total()}} 个类型</td>
+					</tr>
+				</tbody>
+
+			</table>
+		</div>
+	</div>
+</div>
+@endsection

+ 86 - 0
resources/views/admin/video_exam_answer/index.blade.php

@@ -0,0 +1,86 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+
+<form action="" method="get" class="form-horizontal form-line" name="thisform">
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-12" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="record_id" value="{{request('record_id','')}}" placeholder="请输入记录ID查询" />
+	</div>
+	<div class="form-group col col-lg-2 col-md-4 col-sm-6 col-xs-12" style="margin-right: 2px;">
+		<select name="course_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索课程名称" data-none-results-text="未搜索到 {0}" title="选择课程名称">
+			<option value="0" @if( 0 == request('course_id',0) ) selected @endif>不限课程</option>
+			@foreach ($courseList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == request('course_id',0) ) selected @endif>{{$value['name']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-12" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="custom_code" value="{{request('custom_code','')}}" placeholder="请输入客户编码查询" />
+	</div>
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-12" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="custom_name" value="{{request('custom_name','')}}" placeholder="请输入客户昵称查询" />
+	</div>
+	<div class="form-group col col-xs-4 col-md-2" style="margin-right: 2px;">
+		<button type="button" onclick="alter_from_attr({'method':'get','action':''})" class="btn btn-sm btn-primary" style="margin-right: 20px;"> 查询</button>
+		<a href="{{url('admin/video_exam_answer/index')}}" class="btn btn-sm btn-default"  style="margin-right: 20px;" >重置</a>
+		@if( check_auth('admin/video_exam_answer/down_excel') )
+		<button type="button" onclick="alter_from_attr({'method':'get','action':`{{url('admin/video_exam_answer/down_excel')}}`})" class="btn btn-sm btn-primary"> 下载表格</button>
+		@endif
+	</div>
+</form>
+
+<div class="row">
+	<div class="col-xs-12">	
+		<div class="table-responsive">
+			<table class="table table-striped table-bordered table-hover">
+				<thead>
+					<tr>
+						<th>ID</th>
+						<th>课程名称</th>
+						<th>客户编码</th>
+						<th>客户昵称</th>
+						<th>习题题目</th>
+						<th>习题选项</th>
+						<th>所得积分</th>
+						<th>答题时间</th>
+						<th>操作</th>									
+					</tr>
+				</thead>
+				
+				<tbody>
+						@foreach ($list as $a)
+						<tr>
+							<th>{{$a['id']}}</th>
+							<td>{{$a['course_name']}}</td>
+							<td>{{$a['custom_code']}}</td>
+							<td>{{$a['custom_name']}}</td>
+							<td>{{$a['question_title']}}</td>
+							<td>
+								@foreach ($a['answer_list'] as $v)
+								<p @if( $a['answer_id'] == $v['id'] )   @if( $a['is_answer'] )  class="text-green" @else class="text-red"  @endif  @endif>
+									{{$v['value']}} @if($v['is_answer']) 【○】 @endif
+								</p>
+								@endforeach
+							</td>
+							<td>{{$a['get_score']}}</td>
+							<td> {{date('Y/m/d H:i:s',$a['insert_time'])}}</td>
+							<td>
+								
+							</td>							
+						</tr>  
+						@endforeach
+						<tr>
+							<td colspan="20" class="page">{{$list->render()}}</td>
+						</tr>
+						<tr>
+							<td colspan="20">总计 {{$list->total()}} 个记录</td>
+						</tr>
+				</tbody>
+				
+			</table>
+		</div>
+	</div>
+</div>
+@endsection

+ 28 - 0
resources/views/admin/video_exam_question/add.blade.php

@@ -0,0 +1,28 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<form class="post-form" action="" method="post">
+	<div class="form-group col-sm-4" >
+		<label class="control-label">课程名称</label>
+		<select name="course_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索课程名称" data-none-results-text="未搜索到 {0}" title="选择课程名称">
+			@foreach ($courseList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == request('course_id',0) ) selected @endif>{{$value['name']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-4" >
+		<label class="control-label">选择习题</label>
+		<select name="question_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索习题题目" data-none-results-text="未搜索到 {0}" title="选择习题题目">
+			@foreach ($questionList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == request('question_id',0) ) selected @endif>{{$value['title']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection

+ 29 - 0
resources/views/admin/video_exam_question/edit.blade.php

@@ -0,0 +1,29 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<form class="post-form" action="" method="post">
+	<div class="form-group col-sm-4" >
+		<label class="control-label">课程名称</label>
+		<select name="course_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索课程名称" data-none-results-text="未搜索到 {0}" title="选择课程名称">
+			@foreach ($courseList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == $oldData['course_id'] ) selected @endif>{{$value['name']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-4" >
+		<label class="control-label">选择习题</label>
+		<select name="question_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索习题题目" data-none-results-text="未搜索到 {0}" title="选择习题题目">
+			@foreach ($questionList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == $oldData['question_id'] ) selected @endif>{{$value['title']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input type="hidden" name="id" id="id" value="{{$oldData['id']}}" />
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection

+ 89 - 0
resources/views/admin/video_exam_question/index.blade.php

@@ -0,0 +1,89 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+
+@if(check_auth('admin/video_exam_question/add'))
+	<div class="page-header">
+		<a href="{{url('admin/video_exam_question/add?'.http_build_query(['course_id'=>request('course_id',0)]))}}" class="btn btn-primary">新增</a>
+	</div>
+@endif
+
+<form action="" method="get" class="form-horizontal form-line">
+	<div class="form-group col col-lg-2 col-md-4 col-sm-6 col-xs-12" style="margin-right: 2px;">
+		<select name="course_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索课程名称" data-none-results-text="未搜索到 {0}" title="选择课程名称">
+			<option value="0" @if( 0 == request('course_id',0) ) selected @endif>不限课程</option>
+			@foreach ($courseList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == request('course_id',0) ) selected @endif>{{$value['name']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col col-lg-2 col-md-4 col-sm-6 col-xs-12" style="margin-right: 2px;">
+		<select name="question_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索习题题目" data-none-results-text="未搜索到 {0}" title="选择习题题目">
+			<option value="0" @if( 0 == request('question_id',0) ) selected @endif>不限习题</option>
+			@foreach ($questionList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == request('question_id',0) ) selected @endif>{{$value['title']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<input type="submit" class="btn btn-sm btn-primary" value="查询"/>
+	<a href="{{url('admin/video_exam_question/index')}}" class="btn btn-sm btn-default" >重置</a>
+</form>
+
+<div class="row">
+	<div class="col-xs-12">	
+		<div class="table-responsive">
+			<table class="table table-striped table-bordered table-hover">
+				<thead>
+					<tr>
+						<th>ID</th>
+						<th>课程名称</th>
+						<th>习题题目</th>
+						<th>状态</th>
+						<th>修改时间</th>
+						<th>操作</th>									
+					</tr>
+				</thead>
+				
+				<tbody>
+						@foreach ($list as $a)
+						<tr>
+							<th>{{$a['id']}}</th>
+							<td>{{$a['course_name']}}</td>
+							<td>{{$a['question_title']}}</td>
+							<td>
+								@if( $a['status'] )
+								停用
+								@else
+								启用
+								@endif
+							</td>
+							<td> {{date('Y/m/d H:i:s',$a['update_time'])}}</td>
+							<td>
+								@if(check_auth('admin/video_exam_question/edit'))
+								<a href="{{url('admin/video_exam_question/edit?'.http_build_query(['id'=>$a['id']]))}}" class="btn btn-sm btn-warning" >编辑</a>
+								@endif
+								@if(check_auth('admin/video_exam_question/set_status'))
+									@if($a['status'])
+									<a data-url="{{url('admin/video_exam_question/set_status?'.http_build_query(['id'=>$a['id'],'status'=>0]))}}" class="set_status btn btn-sm btn-success" >启用</a>
+									@else
+									<a data-url="{{url('admin/video_exam_question/set_status?'.http_build_query(['id'=>$a['id'],'status'=>1]))}}" class="set_status btn btn-sm btn-danger" >停用</a>
+									@endif
+								@endif
+							</td>							
+						</tr>  
+						@endforeach
+						<tr>
+							<td colspan="20" class="page">{{$list->render()}}</td>
+						</tr>
+						<tr>
+							<td colspan="20">总计 {{$list->total()}} 个题目</td>
+						</tr>
+				</tbody>
+				
+			</table>
+		</div>
+	</div>
+</div>
+@endsection

+ 78 - 0
resources/views/admin/video_exam_record/index.blade.php

@@ -0,0 +1,78 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+
+<form action="" method="get" class="form-horizontal form-line">
+	<div class="form-group col col-lg-2 col-md-4 col-sm-6 col-xs-12" style="margin-right: 2px;">
+		<select name="course_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索课程名称" data-none-results-text="未搜索到 {0}" title="选择课程名称">
+			<option value="0" @if( 0 == request('course_id',0) ) selected @endif>不限课程</option>
+			@foreach ($courseList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == request('course_id',0) ) selected @endif>{{$value['name']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-12" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="custom_code" value="{{request('custom_code','')}}" placeholder="请输入客户编码查询" />
+	</div>
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-12" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="custom_name" value="{{request('custom_name','')}}" placeholder="请输入客户昵称查询" />
+	</div>
+	<input type="submit" class="btn btn-sm btn-primary" value="查询"/>
+	<a href="{{url('admin/video_learn_question/index')}}" class="btn btn-sm btn-default" >重置</a>
+</form>
+
+<div class="row">
+	<div class="col-xs-12">	
+		<div class="table-responsive">
+			<table class="table table-striped table-bordered table-hover">
+				<thead>
+					<tr>
+						<th>ID</th>
+						<th>课程名称</th>
+						<th>客户编码</th>
+						<th>客户昵称</th>
+						<th>正确率</th>
+						<th>所得积分</th>
+						<th>答题时长</th>
+						<th>开始时间</th>
+						<th>结束时间</th>
+						<th>操作</th>									
+					</tr>
+				</thead>
+				
+				<tbody>
+						@foreach ($list as $a)
+						<tr>
+							<th>{{$a['id']}}</th>
+							<td>{{$a['course_name']}}</td>
+							<td>{{$a['custom_code']}}</td>
+							<td>{{$a['custom_name']}}</td>
+							<td>{{$a['right_ratio']}}%</td>
+							<td>{{$a['get_score']}}</td>
+							<td>{{$a['exam_time']}}</td>
+							<td> {{date('Y/m/d H:i:s',$a['start_time'])}}</td>
+							<td> {{$a['end_time'] ? date('Y/m/d H:i:s',$a['end_time']) : ''}}</td>
+							<td>
+								@if( check_auth('admin/video_exam_answer/edit') )
+								<a class="btn btn-sm btn-primary" href="{{url('admin/video_exam_answer/index?'.http_build_query(['course_id'=>$a['course_id'],'record_id'=>$a['id']]))}}" title="答题记录">
+								课后答题记录
+								</a>
+								@endif
+							</td>
+						</tr>  
+						@endforeach
+						<tr>
+							<td colspan="20" class="page">{{$list->render()}}</td>
+						</tr>
+						<tr>
+							<td colspan="20">总计 {{$list->total()}} 个记录</td>
+						</tr>
+				</tbody>
+				
+			</table>
+		</div>
+	</div>
+</div>
+@endsection

+ 86 - 0
resources/views/admin/video_learn_answer/index.blade.php

@@ -0,0 +1,86 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+
+<form action="" method="get" class="form-horizontal form-line">
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-12" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="record_id" value="{{request('record_id','')}}" placeholder="请输入记录ID查询" />
+	</div>
+	<div class="form-group col col-lg-2 col-md-4 col-sm-6 col-xs-12" style="margin-right: 2px;">
+		<select name="course_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索课程名称" data-none-results-text="未搜索到 {0}" title="选择课程名称">
+			<option value="0" @if( 0 == request('course_id',0) ) selected @endif>不限课程</option>
+			@foreach ($courseList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == request('course_id',0) ) selected @endif>{{$value['name']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-12" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="custom_code" value="{{request('custom_code','')}}" placeholder="请输入客户编码查询" />
+	</div>
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-12" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="custom_name" value="{{request('custom_name','')}}" placeholder="请输入客户昵称查询" />
+	</div>
+	<div class="form-group col col-xs-4 col-md-2" style="margin-right: 2px;">
+		<button type="button" onclick="alter_from_attr({'method':'get','action':''})" class="btn btn-sm btn-primary"  style="margin-right: 20px;" > 查询</button>
+		<a href="{{url('admin/video_learn_answer/index')}}" class="btn btn-sm btn-default"  style="margin-right: 20px;" >重置</a>
+		@if( check_auth('admin/video_learn_answer/down_excel') )
+		<button type="button" onclick="alter_from_attr({'method':'get','action':`{{url('admin/video_learn_answer/down_excel')}}`})" class="btn btn-sm btn-primary"> 下载表格</button>
+		@endif
+	</div>
+</form>
+
+<div class="row">
+	<div class="col-xs-12">	
+		<div class="table-responsive">
+			<table class="table table-striped table-bordered table-hover">
+				<thead>
+					<tr>
+						<th>ID</th>
+						<th>课程名称</th>
+						<th>客户编码</th>
+						<th>客户昵称</th>
+						<th>习题题目</th>
+						<th>习题选项</th>
+						<th>所得积分</th>
+						<th>答题时间</th>
+						<th>操作</th>									
+					</tr>
+				</thead>
+				
+				<tbody>
+						@foreach ($list as $a)
+						<tr>
+							<th>{{$a['id']}}</th>
+							<td>{{$a['course_name']}}</td>
+							<td>{{$a['custom_code']}}</td>
+							<td>{{$a['custom_name']}}</td>
+							<td>{{$a['question_title']}}</td>
+							<td>
+								@foreach ($a['answer_list'] as $v)
+								<p @if( $a['answer_id'] == $v['id'] )   @if( $a['is_answer'] )  class="text-green" @else class="text-red"  @endif  @endif>
+									{{$v['value']}} @if($v['is_answer']) 【○】 @endif 
+								</p>
+								@endforeach
+							</td>
+							<td>{{$a['get_score']}}</td>
+							<td> {{date('Y/m/d H:i:s',$a['insert_time'])}}</td>
+							<td>
+								
+							</td>							
+						</tr>  
+						@endforeach
+						<tr>
+							<td colspan="20" class="page">{{$list->render()}}</td>
+						</tr>
+						<tr>
+							<td colspan="20">总计 {{$list->total()}} 个记录</td>
+						</tr>
+				</tbody>
+				
+			</table>
+		</div>
+	</div>
+</div>
+@endsection

+ 39 - 0
resources/views/admin/video_learn_question/add.blade.php

@@ -0,0 +1,39 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<form class="post-form" action="" method="post">
+	<div class="form-group col-sm-4" >
+		<label class="control-label">课程名称</label>
+		<select name="course_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索课程名称" data-none-results-text="未搜索到 {0}" title="选择课程名称">
+			@foreach ($courseList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == request('course_id',0) ) selected @endif>{{$value['name']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-4" >
+		<label class="control-label">选择习题</label>
+		<select name="question_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索习题题目" data-none-results-text="未搜索到 {0}" title="选择习题题目">
+			@foreach ($questionList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == request('question_id',0) ) selected @endif>{{$value['title']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-4">
+		<label class="control-label">出题时间(00:00)</label>
+		<div class="form-group col-sm-12">
+			<div class="form-group col-sm-6">
+				<input class="form-control" required="required" type="number" placeholder="分" name="minute" min="1" max="255" value="00" />
+			</div>
+			<div class="form-group col-sm-6">
+				<input class="form-control" required="required" type="number" placeholder="秒" name="second" min="0" max="60" value="00" />
+			</div>
+		</div>
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection

+ 40 - 0
resources/views/admin/video_learn_question/edit.blade.php

@@ -0,0 +1,40 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<form class="post-form" action="" method="post">
+	<div class="form-group col-sm-4" >
+		<label class="control-label">课程名称</label>
+		<select name="course_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索课程名称" data-none-results-text="未搜索到 {0}" title="选择课程名称">
+			@foreach ($courseList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == $oldData['course_id'] ) selected @endif>{{$value['name']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-4" >
+		<label class="control-label">选择习题</label>
+		<select name="question_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索习题题目" data-none-results-text="未搜索到 {0}" title="选择习题题目">
+			@foreach ($questionList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == $oldData['question_id'] ) selected @endif>{{$value['title']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col-sm-4">
+		<label class="control-label">出题时间(00:00)</label>
+		<div class="form-group col-sm-12">
+			<div class="form-group col-sm-6">
+				<input class="form-control" required="required" type="number" placeholder="分" name="minute" min="1" max="255" value="{{$oldData['minute']}}" />
+			</div>
+			<div class="form-group col-sm-6">
+				<input class="form-control" required="required" type="number" placeholder="秒" name="second" min="0" max="60" value="{{$oldData['second']}}" />
+			</div>
+		</div>
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input type="hidden" name="id" id="id" value="{{$oldData['id']}}" />
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection

+ 91 - 0
resources/views/admin/video_learn_question/index.blade.php

@@ -0,0 +1,91 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+
+@if(check_auth('admin/video_learn_question/add'))
+	<div class="page-header">
+		<a href="{{url('admin/video_learn_question/add?'.http_build_query(['course_id'=>request('course_id',0)]))}}" class="btn btn-primary">新增</a>
+	</div>
+@endif
+
+<form action="" method="get" class="form-horizontal form-line">
+	<div class="form-group col col-lg-2 col-md-4 col-sm-6 col-xs-12" style="margin-right: 2px;">
+		<select name="course_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索课程名称" data-none-results-text="未搜索到 {0}" title="选择课程名称">
+			<option value="0" @if( 0 == request('course_id',0) ) selected @endif>不限课程</option>
+			@foreach ($courseList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == request('course_id',0) ) selected @endif>{{$value['name']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col col-lg-2 col-md-4 col-sm-6 col-xs-12" style="margin-right: 2px;">
+		<select name="question_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索习题题目" data-none-results-text="未搜索到 {0}" title="选择习题题目">
+			<option value="0" @if( 0 == request('question_id',0) ) selected @endif>不限习题</option>
+			@foreach ($questionList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == request('question_id',0) ) selected @endif>{{$value['title']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<input type="submit" class="btn btn-sm btn-primary" value="查询"/>
+	<a href="{{url('admin/video_learn_question/index')}}" class="btn btn-sm btn-default" >重置</a>
+</form>
+
+<div class="row">
+	<div class="col-xs-12">	
+		<div class="table-responsive">
+			<table class="table table-striped table-bordered table-hover">
+				<thead>
+					<tr>
+						<th>ID</th>
+						<th>课程名称</th>
+						<th>出题时间</th>
+						<th>习题题目</th>
+						<th>状态</th>
+						<th>修改时间</th>
+						<th>操作</th>									
+					</tr>
+				</thead>
+				
+				<tbody>
+						@foreach ($list as $a)
+						<tr>
+							<th>{{$a['id']}}</th>
+							<td>{{$a['course_name']}}</td>
+							<td>{{$a['play_time']}}</td>
+							<td>{{$a['question_title']}}</td>
+							<td>
+								@if( $a['status'] )
+								停用
+								@else
+								启用
+								@endif
+							</td>
+							<td> {{date('Y/m/d H:i:s',$a['update_time'])}}</td>
+							<td>
+								@if(check_auth('admin/video_learn_question/edit'))
+								<a href="{{url('admin/video_learn_question/edit?'.http_build_query(['id'=>$a['id']]))}}" class="btn btn-sm btn-warning" >编辑</a>
+								@endif
+								@if(check_auth('admin/video_learn_question/set_status'))
+									@if($a['status'])
+									<a data-url="{{url('admin/video_learn_question/set_status?'.http_build_query(['id'=>$a['id'],'status'=>0]))}}" class="set_status btn btn-sm btn-success" >启用</a>
+									@else
+									<a data-url="{{url('admin/video_learn_question/set_status?'.http_build_query(['id'=>$a['id'],'status'=>1]))}}" class="set_status btn btn-sm btn-danger" >停用</a>
+									@endif
+								@endif
+							</td>							
+						</tr>  
+						@endforeach
+						<tr>
+							<td colspan="20" class="page">{{$list->render()}}</td>
+						</tr>
+						<tr>
+							<td colspan="20">总计 {{$list->total()}} 个题目</td>
+						</tr>
+				</tbody>
+				
+			</table>
+		</div>
+	</div>
+</div>
+@endsection

+ 80 - 0
resources/views/admin/video_learn_record/index.blade.php

@@ -0,0 +1,80 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+
+<form action="" method="get" class="form-horizontal form-line">
+	<div class="form-group col col-lg-2 col-md-4 col-sm-6 col-xs-12" style="margin-right: 2px;">
+		<select name="course_id" class="form-control selectpicker" data-live-search="true" data-live-search-placeholder="搜索课程名称" data-none-results-text="未搜索到 {0}" title="选择课程名称">
+			<option value="0" @if( 0 == request('course_id',0) ) selected @endif>不限课程</option>
+			@foreach ($courseList as $value)
+				<option value="{{$value['id']}}" @if( $value['id'] == request('course_id',0) ) selected @endif>{{$value['name']}}</option>
+			@endforeach
+		</select>
+	</div>
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-12" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="custom_code" value="{{request('custom_code','')}}" placeholder="请输入客户编码查询" />
+	</div>
+	<div class="form-group col col-lg-2 col-md-2 col-sm-2 col-xs-12" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="custom_name" value="{{request('custom_name','')}}" placeholder="请输入客户昵称查询" />
+	</div>
+	<input type="submit" class="btn btn-sm btn-primary" value="查询"/>
+	<a href="{{url('admin/video_learn_question/index')}}" class="btn btn-sm btn-default" >重置</a>
+</form>
+
+<div class="row">
+	<div class="col-xs-12">	
+		<div class="table-responsive">
+			<table class="table table-striped table-bordered table-hover">
+				<thead>
+					<tr>
+						<th>ID</th>
+						<th>课程名称</th>
+						<th>客户编码</th>
+						<th>客户昵称</th>
+						<th>正确率</th>
+						<th>所得积分</th>
+						<th>视频学习开始时间</th>
+						<th>视频学习结束时间</th>
+						<th>开始时间</th>
+						<th>结束时间</th>
+						<th>操作</th>									
+					</tr>
+				</thead>
+				
+				<tbody>
+						@foreach ($list as $a)
+						<tr>
+							<th>{{$a['id']}}</th>
+							<td>{{$a['course_name']}}</td>
+							<td>{{$a['custom_code']}}</td>
+							<td>{{$a['custom_name']}}</td>
+							<td>{{$a['right_ratio']}}%</td>
+							<td>{{$a['get_score']}}</td>
+							<td>{{$a['video_inittime']}}</td>
+							<td>{{$a['video_lasttime']}}</td>
+							<td> {{date('Y/m/d H:i:s',$a['start_time'])}}</td>
+							<td> {{$a['end_time'] ? date('Y/m/d H:i:s',$a['end_time']) : ''}}</td>
+							<td>
+								@if( check_auth('admin/video_learn_answer/edit') )
+								<a class="btn btn-sm btn-primary" href="{{url('admin/video_learn_answer/index?'.http_build_query(['course_id'=>$a['course_id'],'record_id'=>$a['id']]))}}" title="答题记录">
+									课中答题记录
+								</a>
+								@endif
+							</td>							
+						</tr>  
+						@endforeach
+						<tr>
+							<td colspan="20" class="page">{{$list->render()}}</td>
+						</tr>
+						<tr>
+							<td colspan="20">总计 {{$list->total()}} 个记录</td>
+						</tr>
+				</tbody>
+				
+			</table>
+		</div>
+	</div>
+</div>
+@endsection

+ 20 - 0
resources/views/admin/video_question/add.blade.php

@@ -0,0 +1,20 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<form class="post-form" action="" method="post">
+	<div class="form-group col-sm-12">
+		<label class="control-label">题目</label>
+		<input class="form-control" required="required" type="text" placeholder="题目标题" name="title" maxlength="255" value="" />
+	</div>
+	<div class="form-group col-sm-12">
+		<label class="control-label">积分</label>
+		<input class="form-control" required="required" type="number" placeholder="答题积分" name="score"  value="0" />
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection

+ 21 - 0
resources/views/admin/video_question/edit.blade.php

@@ -0,0 +1,21 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+<form class="post-form" action="" method="post">
+	<div class="form-group col-sm-12">
+		<label class="control-label">题目标题</label>
+		<input class="form-control" required="required" type="text" placeholder="题目标题" name="title" maxlength="255" value="{{$oldData['title']}}" />
+	</div>
+	<div class="form-group col-sm-12">
+		<label class="control-label">积分</label>
+		<input class="form-control" required="required" type="number" placeholder="答题积分" name="score"  value="{{$oldData['score']}}" />
+	</div>
+	<div class="form-group col-sm-12">
+		@csrf
+		<input type="hidden" name="id" id="id" value="{{$oldData['id']}}" />
+		<input id="send" type="submit" value="提交" class="btn btn-primary btn-block" />
+	</div>
+</form>
+@endsection

+ 79 - 0
resources/views/admin/video_question/index.blade.php

@@ -0,0 +1,79 @@
+@extends('admin.public.base')
+@section('body_class')
+style="margin: 0 auto;width: 96%;padding: 30px 0px;"
+@endsection
+@section('content')
+
+@if(check_auth('admin/video_question/add'))
+	<div class="page-header">
+		<a href="{{url('admin/video_question/add')}}" class="btn btn-primary">新增</a>
+	</div>
+@endif
+
+<form action="" method="get" class="form-horizontal form-line">
+	<div class="form-group col col-lg-2 col-md-4 col-sm-6 col-xs-12" style="margin-right: 2px;">
+		<input type="text" class="form-control" name="title" value="{{request('title','')}}" placeholder="请输入题目查询" />
+	</div>
+	<input type="submit" class="btn btn-sm btn-primary" value="查询"/>
+	<a href="{{url('admin/video_question/index')}}" class="btn btn-sm btn-default" >重置</a>
+</form>
+
+<div class="row">
+	<div class="col-xs-12">	
+		<div class="table-responsive">
+			<table class="table table-striped table-bordered table-hover">
+				<thead>
+					<tr>
+						<th>ID</th>
+						<th>题目</th>
+						<th>积分</th>
+						<th>状态</th>
+						<th>修改时间</th>
+						<th>操作</th>									
+					</tr>
+				</thead>
+				
+				<tbody>
+						@foreach ($list as $a)
+						<tr>
+							<th>{{$a['id']}}</th>
+							<td>{{$a['title']}}</td>
+							<td>{{$a['score']}}</td>
+							<td>
+								@if( $a['status'] )
+								停用
+								@else
+								启用
+								@endif
+							</td>
+							<td> {{date('Y/m/d H:i:s',$a['update_time'])}}</td>
+							<td>
+								@if(check_auth('admin/video_answer/index'))
+								<a href="{{url('admin/video_answer/index?'.http_build_query(['question_id'=>$a['id']]))}}" class="btn btn-sm btn-primary" >选项</a>
+								@endif
+								@if(check_auth('admin/video_question/edit'))
+								<a href="{{url('admin/video_question/edit?'.http_build_query(['id'=>$a['id']]))}}" class="btn btn-sm btn-warning" >编辑</a>
+								@endif
+								@if(check_auth('admin/video_question/set_status'))
+									@if($a['status'])
+									<a data-url="{{url('admin/video_question/set_status?'.http_build_query(['id'=>$a['id'],'status'=>0]))}}" class="set_status btn btn-sm btn-success" >启用</a>
+									@else
+									<a data-url="{{url('admin/video_question/set_status?'.http_build_query(['id'=>$a['id'],'status'=>1]))}}" class="set_status btn btn-sm btn-danger" >停用</a>
+									@endif
+								@endif
+							</td>							
+						</tr>  
+						@endforeach
+						<tr>
+							<td colspan="20" class="page">{{$list->render()}}</td>
+						</tr>
+						<tr>
+							<td colspan="20">总计 {{$list->total()}} 个题目</td>
+						</tr>
+				</tbody>
+				
+			</table>
+		</div>
+	</div>
+</div>
+@endsection

+ 45 - 1
routes/api.php

@@ -271,8 +271,52 @@ Route::any('riddle_active_share/add',[\App\Http\Controllers\Api\Riddle\ActiveSha
 Route::any('riddle_answer/check_answer',[\App\Http\Controllers\Api\Riddle\Answer::class,'check_answer']);
 
 /**
- * 文章详情
+ * 文章资讯
  */
 Route::any('article/get_list',[App\Http\Controllers\Api\Article\Comment::class,'get_list']);
 Route::any('article/get_detail',[App\Http\Controllers\Api\Article\Comment::class,'get_detail']);
 Route::any('article/update_event',[App\Http\Controllers\Api\Article\Comment::class,'update_event']);
+
+
+/**
+ * 视频课程
+ */
+Route::any('video_course/get_list',[App\Http\Controllers\Api\Video\Course::class,'get_list']);
+Route::any('video_course/get_detail',[App\Http\Controllers\Api\Video\Course::class,'get_detail']);
+
+/**
+ * 更新播放时间
+ * 
+ */
+Route::any('video_learn_record/update_playtime',[App\Http\Controllers\Api\Video\LearnRecord::class,'update_playtime']);
+// 课中习题报告
+Route::any('video_learn_record/get_report',[App\Http\Controllers\Api\Video\LearnRecord::class,'get_report']);
+
+/**
+ * 课中习题
+ */
+// 答题记录
+Route::any('video_learn_answer/get_list',[App\Http\Controllers\Api\Video\LearnAnswer::class,'get_list']);
+// 答题
+Route::any('video_learn_answer/play_exam',[App\Http\Controllers\Api\Video\LearnAnswer::class,'play_exam']);
+
+
+/**
+ * 课后评测习题
+ * 
+ */
+Route::any('video_exam_question/get_list',[App\Http\Controllers\Api\Video\ExamQuestion::class,'get_list']);
+
+/**
+ * 课后答题记录
+ */
+Route::any('video_exam_answer/get_list',[App\Http\Controllers\Api\Video\ExamAnswer::class,'get_list']);
+
+/**
+ * 评测报告
+ * 
+ */
+Route::any('video_exam_record/hand_in',[App\Http\Controllers\Api\Video\ExamRecord::class,'hand_in']);
+Route::any('video_exam_record/get_report',[App\Http\Controllers\Api\Video\ExamRecord::class,'get_report']);
+Route::any('video_exam_record/get_report_last',[App\Http\Controllers\Api\Video\ExamRecord::class,'get_report_last']);
+

+ 83 - 2
routes/web.php

@@ -543,8 +543,8 @@ Route::middleware('admin')->prefix('admin')->group(function(){
     // 拉新活动数据列表
     Route::any('recruitment_record/index',[App\Http\Controllers\Admin\RecruitmentRecord::class,'index']);
     
-    /* 营销管理 */
-    //分享设置列表Promo
+    /* 文章管理 */
+    // 文章
     Route::any('article/index',[App\Http\Controllers\Admin\Article::class,'index']);
     // 新增
     Route::any('article/add',[App\Http\Controllers\Admin\Article::class,'add']);
@@ -659,4 +659,85 @@ Route::middleware('admin')->prefix('admin')->group(function(){
     // 状态
     Route::any('riddle_answer/set_answer',[App\Http\Controllers\Admin\RiddleAnswer::class,'set_answer']);
 
+    /* 视频课程类型管理 */
+    // 文章
+    Route::any('video_course_type/index',[App\Http\Controllers\Admin\VideoCourseType::class,'index']);
+    // 新增
+    Route::any('video_course_type/add',[App\Http\Controllers\Admin\VideoCourseType::class,'add']);
+    // 编辑
+    Route::any('video_course_type/edit',[App\Http\Controllers\Admin\VideoCourseType::class,'edit']);
+    // 状态
+    Route::any('video_course_type/set_status',[App\Http\Controllers\Admin\VideoCourseType::class,'set_status']);
+    // 状态
+    Route::any('video_course_type/get_sign_url',[App\Http\Controllers\Admin\VideoCourseType::class,'get_sign_url']);
+
+    /* 视频课程管理 */
+    // 文章
+    Route::any('video_course/index',[App\Http\Controllers\Admin\VideoCourse::class,'index']);
+    // 新增
+    Route::any('video_course/add',[App\Http\Controllers\Admin\VideoCourse::class,'add']);
+    // 编辑
+    Route::any('video_course/edit',[App\Http\Controllers\Admin\VideoCourse::class,'edit']);
+    // 状态
+    Route::any('video_course/set_status',[App\Http\Controllers\Admin\VideoCourse::class,'set_status']);
+    // 状态
+    Route::any('video_course/get_sign_url',[App\Http\Controllers\Admin\VideoCourse::class,'get_sign_url']);
+
+    /* 课程习题 */
+    // 习题列表
+    Route::any('video_question/index',[App\Http\Controllers\Admin\VideoQuestion::class,'index']);
+    // 详情
+    Route::any('video_question/add',[App\Http\Controllers\Admin\VideoQuestion::class,'add']);
+    // 详情
+    Route::any('video_question/edit',[App\Http\Controllers\Admin\VideoQuestion::class,'edit']);
+    // 状态
+    Route::any('video_question/set_status',[App\Http\Controllers\Admin\VideoQuestion::class,'set_status']);
+
+
+    /* 课程习题 */
+    // 列表
+    Route::any('video_answer/index',[App\Http\Controllers\Admin\VideoAnswer::class,'index']);
+    // 详情
+    Route::any('video_answer/add',[App\Http\Controllers\Admin\VideoAnswer::class,'add']);
+    // 详情
+    Route::any('video_answer/edit',[App\Http\Controllers\Admin\VideoAnswer::class,'edit']);
+    // 状态
+    Route::any('video_answer/set_answer',[App\Http\Controllers\Admin\VideoAnswer::class,'set_answer']);
+
+    /* 课中习题 */
+    // 列表
+    Route::any('video_learn_question/index',[App\Http\Controllers\Admin\VideoLearnQuestion::class,'index']);
+    // 详情
+    Route::any('video_learn_question/add',[App\Http\Controllers\Admin\VideoLearnQuestion::class,'add']);
+    // 详情
+    Route::any('video_learn_question/edit',[App\Http\Controllers\Admin\VideoLearnQuestion::class,'edit']);
+    // 状态
+    Route::any('video_learn_question/set_status',[App\Http\Controllers\Admin\VideoLearnQuestion::class,'set_status']);
+
+    /* 学习记录 */
+    Route::any('video_learn_record/index',[App\Http\Controllers\Admin\VideoLearnRecord::class,'index']);
+
+    /* 学习答题记录 */
+    Route::any('video_learn_answer/index',[App\Http\Controllers\Admin\VideoLearnAnswer::class,'index']);
+    /* 答题记录下载 */
+    Route::any('video_learn_answer/down_excel',[App\Http\Controllers\Admin\VideoLearnAnswer::class,'down_excel']);
+
+    /* 课后习题 */
+    // 列表
+    Route::any('video_exam_question/index',[App\Http\Controllers\Admin\VideoExamQuestion::class,'index']);
+    // 详情
+    Route::any('video_exam_question/add',[App\Http\Controllers\Admin\VideoExamQuestion::class,'add']);
+    // 详情
+    Route::any('video_exam_question/edit',[App\Http\Controllers\Admin\VideoExamQuestion::class,'edit']);
+    // 状态
+    Route::any('video_exam_question/set_status',[App\Http\Controllers\Admin\VideoExamQuestion::class,'set_status']);
+
+    /* 评测记录 */
+    Route::any('video_exam_record/index',[App\Http\Controllers\Admin\VideoExamRecord::class,'index']);
+
+    /* 评测答题记录 */
+    Route::any('video_exam_answer/index',[App\Http\Controllers\Admin\VideoExamAnswer::class,'index']);
+    /* 答题记录下载 */
+    Route::any('video_exam_answer/down_excel',[App\Http\Controllers\Admin\VideoExamAnswer::class,'down_excel']);
+
 });