[TOC]
## 展示效果
http://weike.test/index.php?r=teachingV3/review/sReviewList
![](./img/2018-11-19_110011.png)
![](./img/2018-11-19_110315.png)
## 控制器代码
**D:\wamp\www\xue.test\xuetang\protected\modules\teachingV3\controllers\ReviewController.php**
```
/**
* 学生回顾列表
* @author liupf 2016/9/27
*/
public function actionSReviewList()
{
$this->layout = "//version2/layouts/main_center_v3";
$userID = $this->getSession()->fdUserID;
$schoolMap = UserService::factory()->getSchoolMapByUserID($userID);
if(!$schoolMap)
$this->redirect_msgBox($this->createUrl('/'), array('msg'=>'未加入学校'));
$classes = ClassService::factory()->getAllClassByUserID($userID,WK::CLASS_CLASS);
$classList = array();
if($classes){
foreach($classes as $class){
$classList[]=array(
'id' => $class->id,
'title' => $class->fdName
);
}
}
$classIDArr = ArrayUtils::getColumn($classList,'id');
$schoolTypeArr = SchoolService::factory()->getSchoolType($schoolMap->fdSchoolID);
$subjectIDArr = array();
if($schoolTypeArr){
foreach($schoolTypeArr as $schoolType)
$subjectIDArr = array_merge($subjectIDArr,Yii::app()->params['PARAGRAPH_SUB_INDEX'][$schoolType]);
}
$subjectIDArr = array_unique($subjectIDArr);
if($subjectIDArr){
foreach($subjectIDArr as $subjectID){
$teachings = V3TeachService::factory()->getTeachings(array(
'subjectID' => $subjectID,
'classID' => $classIDArr,
));
if($teachings){
$subjectList[]=array(
'id' => $subjectID,
'title' => Yii::app()->params['SUBJECT_ARR'][$subjectID]
);
}
}
}
$this->render("sReviewList",array(
'classList'=>CJSON::encode($classList), //班级
'subjectList'=>CJSON::encode($subjectList?:array()), //科目
));
}
```
接口:
```
/**
* 获取学生课堂记录
* classID 班级ID 可选
* subjectID 科目ID 可选
* keyword 关键字 可选
* start 需要获取数据的开始位置 可选,默认是0
* len 需要获取数据的结束位置 可选,默认是10
* @author liupf 2016/9/28
*/
public function actionStuRecord(){
$classID = RequestUtils::getNormalRequest('classID');
$subjectID = RequestUtils::getNormalRequest('subjectID');
$keyword = RequestUtils::getNormalRequest('keyword');
$start = RequestUtils::getNormalRequest('start')?:0;
$len = RequestUtils::getNormalRequest('len')?:10;
$subjectInt = RequestUtils::getNormalRequest('subjectInt');
if(!$classID)
ResponseUtils::json(null,1,'failure');
$condition = array('classID'=> $classID,'isOver'=> true);
$data = array();
if($subjectInt){
$data['subjectList'] = V3TeachService::factory()->getSubjectDistribute($condition);
}
$condition['subjectID'] = $subjectID;
$condition['prepareName'] = $keyword;
$condition['with'] = array('content','content.v2version','content.period');
$total = V3TeachService::factory()->countTeaching($condition);
$data['total'] = $total;
$data['record'] = array();
!$total && ResponseUtils::json(array('data'=>$data));
$condition['order'] = 't.id DESC';
$condition['limit'] = intval($len);
$condition['offset'] = intval($start);
$teachings = V3TeachService::factory()->getTeachings($condition);
$data['record'] = $this->_processTeachings($teachings);
ResponseUtils::json(array('data'=>$data));
}
```
完善接口返回的信息
```
/**
* @param $teachings
* @return array
* @author liupf 2016/9/28
*/
private function _processTeachings($teachings)
{
$teachingList=array();
foreach($teachings as $teaching){
$records = V3TeachService::factory()->getStudentRecords(array('teachingID'=>$teaching->id));
$studentIDArr= $records?ArrayUtils::getColumn($records,'fdStudentID'):array();
$studentIDArr= array_unique($studentIDArr);
$teachingList[]=array(
'teachingID'=> $teaching->id,
'prepareID' => $teaching->fdPrepareID,
'title' => $teaching->content->fdName,
'period' => $teaching->content->period->fdValue,
'className' => V2ClassService::factory()->getClass(array('id'=>$teaching->fdClassID))->fdName,
'subject' => Yii::app()->params['SUBJECT_ARR'][$teaching->fdSubjectID],
'version' => wkeVersion::model()->findByPk($teaching->content->v2version->fdValue)->fdName,
'start' => DateTimeUtils::date2MillSecond($teaching->fdStart),
'end' => $teaching->fdEnd ? DateTimeUtils::date2MillSecond($teaching->fdEnd):$teaching->fdEnd,
'tags' => V3RelevanceService::factory()->getTags($teaching->fdPrepareID),
'teacherName'=>UserService::factory()->getShowName($teaching->fdTeacherID, 'ketang'),
'studentInClass'=>count($studentIDArr),
'prepareType'=> V3PrepareService::factory()->getPrepareTypeName($teaching->fdPrepareID),
);
}
return $teachingList;
}
```
数据格式:
```
{
"total": "54",
"record": [{
"teachingID": "5256",
"prepareID": "1528022",
"title": "1.1 正数和负数",
"period": "1",
"className": "一年级50班",
"subject": "数学",
"version": "人教版",
"start": 1488075419000,
"end": null,
"tags": [{
"id": 41489,
"title": "七年级上册",
"level": 1
}, {
"id": 41490,
"title": "第一章 有理数",
"level": 2
}, {
"id": 41491,
"title": "1.1 正数和负数",
"level": 3
}],
"teacherName": "测试老师1",
"studentInClass": 0,
"prepareType": "新授课"
},]
}
```
条件查询方法
**D:\wamp\www\weike.test\weiketest\protected\service\service3\V3TeachService.php**
```
private function _findTeaching($args)
{
$criteria = new CDbCriteria();
$with = array();
if($args['distinct']){
$criteria->distinct = $args['distinct'];
}
CDbUtils::addCondition($criteria, 't.id', $args['id']);
CDbUtils::addCondition($criteria, 't.fdClassID', $args['classID']);
CDbUtils::addCondition($criteria, 't.fdTeacherID', $args['teacherID']);
CDbUtils::addCondition($criteria, 't.fdPrepareID', $args['prepareID']);
CDbUtils::addCondition($criteria, 't.fdGradeID', $args['gradeID']);
/*by liupf 2016/9/28 */
CDbUtils::addCondition($criteria, 't.fdSubjectID', $args['subjectID']);
// add by wuzhc 2018-03-21 0正常,1删除
if(is_numeric($args['status'])){
CDbUtils::addCondition($criteria, 't.fdStatus', intval($args['status']));
}
if($args['studentID']){
$criteria->together =true;
$with[] = 'record';
CDbUtils::addCondition($criteria, 'record.fdStudentID', $args['studentID']);
}
//检测改班级是否还在上课状态
if($args['flag']){
$criteria->addCondition('t.fdStart>DATE_SUB(now(),INTERVAL '.WK::WMPC_CLASS_TIME.' MINUTE )');
$criteria->addCondition('t.fdEnd is NULL') ;
}
/*by liupf 2016/10/18 */
if($args['schoolID']){
$with[] = 'class' ;
CDbUtils::addCondition($criteria, 'class.fdSchoolID', $args['schoolID']);
}
if($args['year']){
$with[] = 'class' ;
CDbUtils::addCondition($criteria, 'class.fdYear', $args['year']);
}
if(isset($args['classStatus'])){
$with[] = 'class' ;
CDbUtils::addCondition($criteria, 'class.fdStatus', $args['classStatus']);
}
if($args['group'] == 1){//以科目分组
$criteria->group = 't.fdSubjectID';
$criteria->select = 't.fdSubjectID,count(*) as total';
}
if($args['group'] == 2){
$criteria->group = 't.fdClassID';
$criteria->select = 't.fdClassID,count(*) as total';
}
if($args['prepareName']){
$with[]='content';
$criteria->addSearchCondition('content.fdName',$args['prepareName']);
}
if($args['keyword'] || (0===$args['keyword'] || '0'===$args['keyword'])){
$with[]='user';
$with[]='content';
$criteria->addCondition("content.fdName LIKE '%".$args['keyword']."%' OR user.fdRealName LIKE '%".$args['keyword']."%'");
}
if($args['teacherName']){
$with[]='user';
$criteria->addSearchCondition('user.fdRealName',$args['teacherName']);
}
if($args['start'] || $args['begin']){
$criteria->addCondition('t.fdStart >= :start') ;
$criteria->params[':start'] = $args['start'] ?:$args['begin'];
}
if($args['end']){
$criteria->addCondition('t.fdStart <= :end') ;
$criteria->params[':end'] = $args['end'] ;
}
if($args['isOver']){
$criteria->addCondition('t.fdStart<DATE_SUB(now(),INTERVAL '.WK::WMPC_CLASS_TIME.' MINUTE ) OR t.fdEnd IS NOT NULL');
}
if($args['hasDispenseExam']){
$with[] = 'operations' ;
$criteria->addCondition('operations.fdTypeID = '.WK::DISPENSE_EXAM_DO.' AND operations.fdValue > 0') ;
}
$args['hasSubjectID'] && $criteria->addCondition('t.fdSubjectID>0 AND t.fdSubjectID<17');
$args['hasGradeID'] && $criteria->addCondition('t.fdGradeID>0 AND t.fdGradeID<14');
if($args['select'])
$criteria->select = $args['select'] ;
/*by liupf 2016/10/18 */
if($args['order'])
$criteria->order = $args['order'];
if($args['groupBy'])
$criteria->group = $args['groupBy'];
$criteria->with = array_unique(array_merge($with, (array)$args['with']));
$args['limit'] and $criteria->limit = $args['limit'];
$args['offset'] and $criteria->offset = $args['offset'];
return $criteria;
}
```
生成的SQL:
```
SELECT
`t`.`id` AS `t0_c0`,
`t`.`fdClassID` AS `t0_c1`,
`t`.`fdTeacherID` AS `t0_c2`,
`t`.`fdPrepareID` AS `t0_c3`,
`t`.`fdSubjectID` AS `t0_c4`,
`t`.`fdGradeID` AS `t0_c5`,
`t`.`fdStart` AS `t0_c6`,
`t`.`fdEnd` AS `t0_c7`,
`t`.`fdNote` AS `t0_c8`,
`t`.`fdReview` AS `t0_c9`,
`t`.`fdStatus` AS `t0_c10`,
`content`.`id` AS `t1_c0`,
`content`.`idString` AS `t1_c1`,
`content`.`fdName` AS `t1_c2`,
`content`.`fdEnglish` AS `t1_c3`,
`content`.`fdTypeID` AS `t1_c4`,
`content`.`fdUserID` AS `t1_c5`,
`content`.`fdSchoolTypeID` AS `t1_c6`,
`content`.`fdSubjectID` AS `t1_c7`,
`content`.`fdKindID` AS `t1_c8`,
`content`.`fdAcronym` AS `t1_c9`,
`content`.`fdPinyin` AS `t1_c10`,
`content`.`fdProviderID` AS `t1_c11`,
`content`.`fdCpID` AS `t1_c12`,
`content`.`fdOperatorID` AS `t1_c13`,
`content`.`fdApproverID` AS `t1_c14`,
`content`.`fdApprove` AS `t1_c15`,
`content`.`fdCreate` AS `t1_c16`,
`content`.`fdExpire` AS `t1_c17`,
`content`.`fdModify` AS `t1_c18`,
`content`.`fdAdapt` AS `t1_c19`,
`content`.`fdHot` AS `t1_c20`,
`content`.`fdBornID` AS `t1_c21`,
`content`.`fdSync` AS `t1_c22`,
`content`.`fdCommentID` AS `t1_c23`,
`content`.`fdDisabled` AS `t1_c24`,
`content`.`fdMongoSync` AS `t1_c25`,
`content`.`fdStatStatus` AS `t1_c26`,
`v2version`.`fdValue` AS `t2_c5`,
`v2version`.`id` AS `t2_c0`,
`period`.`fdValue` AS `t3_c5`,
`period`.`id` AS `t3_c0`
FROM
`wkwke`.`tbTeachingV3` `t`
LEFT OUTER JOIN `wkctn`.`tbContent` `content` ON (
`t`.`fdPrepareID` = `content`.`id`
)
LEFT OUTER JOIN `wkctn`.`tbInteger` `v2version` ON (
`v2version`.`fdContentID` = `content`.`id`
)
LEFT OUTER JOIN `wkctn`.`tbInteger` `period` ON (
`period`.`fdContentID` = `content`.`id`
)
WHERE(((t.fdClassID =2) AND (content.fdName LIKE "%正数%"))AND (t.fdStart < DATE_SUB(now(), INTERVAL 120 MINUTE)OR t.fdEnd IS NOT NULL))
AND (v2version.fdAttributeID = 38)
AND (period.fdAttributeID = 379)
ORDER BY
t.id DESC
LIMIT 10
```
## 视图
**D:\wamp\www\weike.test\weiketest\protected\modules\teachingV3\views\review\sReviewList.php**
```
<div class="v3-content pb20">
<!--面包削导航-->
<div class="f18 font-y gray2 pt20 pb20"><a href="javaScript:">首页</a><span class="ml15 mr15">></span><span>课堂回顾</span></div>
<!--面包削导航 end-->
<!--内容-->
<div class="w clr">
<!--选择-->
<div class="w clr mb10">
<div class="fl w760">
<div class="w">
<div class="fl font-y f15 fb mr10 mt3">按班级查找:</div>
<ul class="fl w640 clr js_class_choise">
<li class="border1 h25 lh25 tc pl10 pr10 pointer fl mr15 mb10 bg5 white border_green" data-id="">全部</li>
</ul>
</div>
<div class="w">
<div class="fl font-y f15 fb mr10 mt3">按科目查找:</div>
<ul class="fl w640 clr js_subject_choise">
<li class="border1 h25 lh25 tc pl10 pr10 pointer fl mr15 mb10 bg5 white border_green" data-id="">全部</li>
</ul>
</div>
</div>
<div class="fr">
<input id="search-input" type="text" class="inputText fl w200" placeholder="输入课程名称查找" style="padding:3px 30px 3px 5px;">
<input id="search-btn" type="button" class="fl inputText_searchBtn mt3" title="搜索">
</div>
</div>
<!--选择 end-->
<div class="w">
<!--列表-->
<div class="w pr min_h300" id="list">
<img src="/public/pc/images/loading.gif" alt="ajax-loader" style="position:absolute;top:50%;left:50%;margin-top:-16px;margin-left:-16px;">
</div>
<!--列表 end-->
<!--分页-->
<div class="w mt30 mb10 clr" id="page">
<ul class="tc paging bc">
<li class="gray">共有100条记录</li>
<li class="paging_but paging_off"><a href="javaScript:">上一页</a></li>
<li class="page"><a class="currentPage" href="JavaScript:void(0)">1</a></li>
<li class="page"><a href="JavaScript:void(0)" onclick="getData('2','10')">2</a></li>
<li class="page"><a href="JavaScript:void(0)" onclick="getData('3','10')">3</a></li>
<li class="page"><a href="JavaScript:void(0)" onclick="getData('4','10')">4</a></li>
<li class="page"><a href="JavaScript:void(0)" onclick="getData('5','10')">5</a></li>
<li class="paging_but"><a onclick="getData('2','10')" href="javaScript:">下一页</a></li>
<li>(1/48)</li>
<li><input type="text" class="w30 h30 box-sizing tc" onkeyup="value=value.replace(/[^\d]/g,'') " onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"></li>
<li class="paging_but"><a href="javaScript:">跳转</a></li>
</ul>
</div>
<!--分页 end-->
</div>
</div>
<!--内容 end-->
</div>
<script type="text/javascript" src="<?php echo Yii::app()->request->baseUrl; ?>/public/common/js/showBox.js"></script>
<script type="text/javascript" src="<?php echo Yii::app()->request->baseUrl; ?>/public/ketang/js/upload-page.js"></script>
<script type="text/javascript" src="<?php echo Yii::app()->request->baseUrl; ?>/public/js/timeformate.js"></script>
<script type="text/javascript">
$(function() {
var classList = <?php echo $classList;?>;
var subjectList = <?php echo $subjectList;?>;
var loading = '<img src="/public/pc/images/loading.gif" alt="ajax-loader" style="position:absolute;top:50%;left:50%;margin-top:-16px;margin-left:-16px;">',
notips = '<p class="f24 orange font-y tc" style="height:300px;line-height:300px;">暂无内容!</p>';
var ajaxAbort = {}, page;
function ajaxDeal(options, scallback, ecallback) {
var tajax = $.ajax({
url: options.url,
type: options.type || "GET",
dataType: options.dataType || "json",
data: options.data || {},
success: function(result) {
// console.log(options.url, result);
if (result.status == 0 || result.msg=='success') {
scallback(result);
} else if (result.status == 401) {
$.showBox({"contents": "请先登录", callBack: function() {
window.location.href = "<?php echo $this->createUrl('//');?>";
}});
} else {
ecallback && ecallback(result);
}
},
error: function(error) {
ecallback && ecallback(error);
}
});
if (options.ajax) {
ajaxAbort[options.ajax] && ajaxAbort[options.ajax].abort();
ajaxAbort[options.ajax] = tajax;
}
}
// 课堂记录模板(单个)
function recordTmp(obj) {
var url = obj.prepareID && obj.teachingID ? ('<?php echo $this->createUrl("review/sReview")?>&prepareID=' + obj.prepareID + '&teachingID=' + obj.teachingID) : "javaScript:void(0)";
var tags = obj.tags || [], used = obj.end && obj.start ? (obj.end - obj.start) / 1000 : (2 * 3600);
var second = used % 60, minute = parseInt(used / 60);
tags.sort(function(a, b){return a.level - b.level;});
return '<div class="v3-lesson-index-listOne clr">'
+ '<div class="fl w540">'
+ '<h3>'
+ '<a href="' + url + '" target="_blank">'
+ '<span class="f16 fb vm font-y">【第' + (obj.period || 1) + '课时】' + (obj.title || "未知") + ' </span>'
+ '<span class="classType">' + (obj.prepareType || "新授课") + '</span>'
+ '</a>'
+ '</h3>'
+ '<div class="mt20 clr gray">'
+ '<div class="fl">' + (obj.subject || "未知科目") + '(' + (obj.version || "未知版本") + ')' + (tags[0] ? tags[0].title || "未知教材" : "未知教材") + ' | ' + (tags[1] ? tags[1].title || "" : "") + ' ' + (tags[2] ? tags[2].title || "" : "") + ' ' + (tags[3] ? tags[3].title || "" : "") + '</div>'
+ '</div>'
+ '</div>'
+ '<div class="fr">'
+ '<div class="tr">'
+ '<span class="v3-review-peoIcon"></span>'
+ '<span class="vm ml10">出勤' + (obj.studentInClass || "0")+ '人</span>'
+ '<span class="v3-review-timeIcon ml30"></span>'
+ '<span class="vm ml10">用时' + (minute < 10 ? "0" + minute : minute) + '分' + (second < 10 ? "0" + second : second) + '秒</span>'
+ '</div>'
+ '<div class="tr f13 mt20 gray">'
+ '<span>【' + (obj.teacherName || "未知教师") + '】</span>'
+ '<span class="ml20">【' + (obj.className ||"未知班级") + '】</span>'
+ '<span class="ml20">上课时间:' + (obj.start ? timeFormat(obj.start, "yyyy年MM月dd日HH:mm") : "未知") + '</span>'
+ '</div>'
+ '</div>'
+ '</div>';
}
// 获取课堂回顾记录分页
function getRecords(pa) {
page = new UpLoadPage({
len: 10,
$el: $("#page"),
callback: getRecordHandle,
params: {
pa: pa || {},
$list: $("#list"),
url: "<?php echo $this->createUrl('review/stuRecord');?>"
}
});
page.init();
}
// 获取课堂回顾记录回调
function getRecordHandle(pa) {
var $list = pa.$list;
var pdata = pa.pa;
pdata.start = pa.start;
pdata.len = pa.len;
$list.html(loading);
ajaxDeal({
url: pa.url,
data: pdata,
ajax: "reAbort"
}, function(data) {
data = data.data || {};
var list = data.record || [];
if (list.length > 0) {
var html = "";
for (var i = 0, len = list.length; i < len; i++) {
html += recordTmp(list[i]);
}
$list.html(html);
pa.page.setPage(data.total);
} else {
$list.html(notips);
}
}, function(error) {
if (error.statusText != "abort") {
$list.html(notips);
}
});
}
// 搜索回调
function searchHandle() {
getRecords({
classID: $(".js_class_choise li.border_green").data("id"),
subjectID: $(".js_subject_choise li.border_green").data("id"),
keyword: $("#search-input").val()
});
}
// 初始化
~function init() {
var html = '';
for (var i = 0, len = classList.length; i < len; i++) {
html += '<li class="border1 h25 lh25 tc pl10 pr10 pointer fl mr15 mb10 ' + (i == 0 ? 'bg5 white border_green' : '') + '" data-id="' + classList[i].id + '">' + classList[i].title + '</li>';
}
$(".js_class_choise").html(html);
var shtml = '<li class="border1 h25 lh25 tc pl10 pr10 pointer fl mr15 mb10 bg5 white border_green" data-id="">全部</li>';
for (var i = 0, len = subjectList.length; i < len; i++) {
shtml += '<li class="border1 h25 lh25 tc pl10 pr10 pointer fl mr15 mb10" data-id="' + subjectList[i].id + '">' + subjectList[i].title + '</li>';
}
$(".js_subject_choise").html(shtml);
getRecords({
classID: classList[0].id
});
}();
// 切换班级
$(".js_class_choise").on('click', 'li', function() {
if ($(this).hasClass('.border_green')) return false;
$(this).addClass('bg5 white border_green').siblings('li').removeClass('bg5 white border_green');
getRecords({
subjectID: $(".js_subject_choise li.border_green").data("id"),
classID: $(this).data("id")
});
});
// 切换学科
$(".js_subject_choise").on('click', 'li', function() {
if ($(this).hasClass('.border_green')) return false;
$(this).addClass('bg5 white border_green').siblings('li').removeClass('bg5 white border_green');
getRecords({
subjectID: $(this).data("id"),
classID: $(".js_class_choise li.border_green").data("id")
});
});
// 搜素按钮点击事件
$("#search-btn").on("click", function() {
searchHandle();
});
// 搜索输入回车响应
$("#search-input").on("keypress", function() {
if (event.which == 13){
searchHandle();
}
});
})
</script>
```
## 运行逻辑
![](./img/2018-11-19_112446.png)
![](./img/2018-11-19_112709.png)
![](./img/2018-11-19_112734.png)
![](./img/2018-11-19_112755.png)
![](./img/2018-11-19_112903.png)
- 说明
- 开发任务
- 星课-真光
- 课表
- Excel Down
- 调课
- 课表修改
- 课表代码分析
- 课堂
- 课堂:应用商店通信管理协议
- 教师账号强制绑定手机或邮箱
- 强制绑定手机和修改密码的规则
- 学堂
- 课程学习:讨论功能
- 后台:课程讨论管理
- 课程直播接口
- 学习统计功能(旧版)
- 学习统计功能(新版)
- 同步课程统计功能
- 同步课程编辑-新增视频
- 第三方接口
- 学科网
- 安徽第三方
- 大赛
- 管控系统
- 日志管理
- 设备日志
- 平板接口
- 渝教
- 教学总结
- 空白目录
- Yii 1.1
- 学堂架构
- Yii 1.1一些方法的解读
- MVCS结构
- 基础使用语法
- 创建1个新模块
- 关联模型
- CDbCriteria
- 学生-课堂记录
- 学生端页面展示
- 教师端页面展示
- 编辑课程文档
- SQL
- 课堂项目运行入口
- 上传资源示意图
- 行为
- PHPStorm
- 源码阅读
- 会诊答卷页面
- 考点练习
- 资源首页
- 同步课程
- 同步课程:章节信息
- 升学复习
- 统计图-范例
- 模块
- 非法词
- 服务层
- MongoDB类
- 学堂作答记录从Mongo新集合获取数据
- MongoYii
- 错题集
- 小技巧
- 完善资料
- 邮件发送
- K12
- JSpang视频课程
- MongoDB
- 创业
- 项目
- 包包