TeachingMethod.php 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642
  1. <?php
  2. class TeachingMethod
  3. {
  4. private $subjectId;
  5. private $schoolId = 0;
  6. private $examId = 0;
  7. private $classId = 0;
  8. private $examGroupId = 0;
  9. private $error = array();
  10. private $controllerObj = null;//controller对象
  11. private $examObj = null;
  12. private $sprObj = null;
  13. private $sptRsObj = null;
  14. private $productType;
  15. private $paperTopicIds = array();
  16. //TODO 全学科题库 题型方法对应栏目id
  17. const FULLTEXT_COLUMN_ID = 154; //方法释义富文本
  18. const CLASSIC_COLUMN_ID = 155; //典型例题
  19. const SPECIAL_COLUMN_ID = 228; //方法专练
  20. public function __construct(&$controllerObj)
  21. {
  22. $this->controllerObj = $controllerObj;
  23. $documentRoot = Yii::app()->basePath . "/../";
  24. require_once($documentRoot."lib/plugins/topic-html/vendor/autoload.php");
  25. }
  26. /**
  27. * 生成PDF返回PDF地址
  28. * @param $schoolId
  29. * @param $examId
  30. * @param $productType
  31. * @param $subjectId
  32. * @param int $force
  33. * @param int $viewHtml
  34. * @return array
  35. */
  36. public function getTeachingPdf($schoolId,$examId,$productType,$subjectId,$force = 0,$viewHtml = 0)
  37. {
  38. if (!$schoolId) {
  39. $this->errorMsg(0, '学校ID不正确!');
  40. }
  41. $this->schoolId = $schoolId;
  42. if(!$examId || !is_numeric($examId)){
  43. $this->errorMsg(0, '考试ID参数不正确!');
  44. }
  45. if (!$this->error) {
  46. $force = $viewHtml ? 1 : 0;
  47. if (is_cli()) {
  48. $force = 1;
  49. }
  50. $this->examId = $examId;
  51. $this->subjectId = $productType;
  52. $this->productType = $productType;
  53. //教师版记录初始化
  54. SExamTeachingProduct::model()->initialize($examId,$productType,$subjectId);
  55. $this->examObj = new SExamTeachingProduct();
  56. $examInfo = $this->examObj->getTeachingInfo($examId);
  57. if(!$examInfo){
  58. $this->errorMsg(0, '没有考试信息!');
  59. }
  60. }
  61. if (!$this->error) {
  62. if($examInfo['subject_id']){
  63. $this->subjectId = $examInfo['subject_id'];
  64. $this->examGroupId = $examInfo['exam_group_id'];
  65. $this->classId = $examInfo['class_id'];
  66. }
  67. $pdfurl = $examInfo['pdf_path'];
  68. $res = array();//生成pdf命令结果
  69. if(strpos($examInfo['pdf_path'],'http') !== false){
  70. $force = 0;
  71. }else{
  72. $force = 1;
  73. }
  74. if ($examInfo['pdf_path'] && !$force) {
  75. //文件已生成不再生成
  76. $result = array(
  77. 'status' => 0,
  78. 'error' => '',
  79. 'is_create' => 1,
  80. 'pdf_url' => $pdfurl,
  81. 'pdf_path' => '',
  82. 'file_name' => sprintf("%s_%s_方法宝教学宝",$examInfo['exam_name'],$examInfo['class_name'])
  83. );
  84. return $result;
  85. }
  86. }
  87. if (!$this->error) {
  88. $paperObj = new SPaper();
  89. $ptrObj = new SPaperTopicRelation();
  90. $this->sprObj = new SStudentPaperRelation();
  91. $this->sptRsObj = new SStudentPaperTopicRs();
  92. /**************************** 一、班级情况分析 ***********************************/
  93. //当前考试需要的数据
  94. $actionRs = $this->curExamNeedData($this->sprObj ,$paperObj);
  95. if ($actionRs) {
  96. list($paperId, $paperScore, $examStuScore, $absentStu) = $actionRs;
  97. }
  98. //上次考试需要的数据
  99. if (!$this->error) {
  100. $actionRs = $this->preExamNeedData($examInfo,$this->sprObj,$paperObj);
  101. if ($actionRs) {
  102. list($prePaperScore, $preExamStuScore, $preAbsent) = $actionRs;
  103. }
  104. }
  105. //班级排名得分率人数等数据
  106. if (!$this->error) {
  107. $classAnalyseArr = $this->getClassAnalyse($paperScore,$examStuScore,$prePaperScore, $preExamStuScore, $absentStu, $preAbsent);
  108. }
  109. //大幅进步,大幅退步,前5名和后5名($needStudentArr:得分大于0的学生)
  110. if (!$this->error) {
  111. list($largeOrderArr,$needStudentArr) = $this->getLargeOrder($examStuScore,$preExamStuScore,$absentStu,$preAbsent);
  112. }
  113. unset($preExamStuScore);
  114. /**************************** 二、考试情况分析 ***********************************/
  115. $is_qxk_page = (isset($examInfo["qxk_paper_id"]) && $examInfo["qxk_paper_id"])?1:0;
  116. if (!$this->error) {
  117. $paperTopicInfo = $ptrObj->getPaperInfo($paperId);
  118. if(!$paperTopicInfo){
  119. $this->errorMsg(0, '没有试卷题数据!');
  120. }else{
  121. $topicScoreArr = array();
  122. foreach ($paperTopicInfo as $item) {
  123. $topicScoreArr[$item['topic_id']] = $item['score'];
  124. }
  125. $tplDataArr = json_decode($examInfo['tpl_data'], true);
  126. //$topicNoArr = $this->getTopicNoArr($paperTopicInfo, $tplDataArr);
  127. $changeDoTopicNoArr = $this->getChangeDoToicNoArr($paperTopicInfo, $tplDataArr);
  128. $topicNoArr = SPaperTopicRelation::model()->getPaperTopicDetailById($paperId,$tplDataArr,$is_qxk_page,$changeDoTopicNoArr);
  129. $topicIdsArr = array_keys($topicNoArr);
  130. $this->paperTopicIds = $topicIdsArr;
  131. unset($paperTopicInfo);
  132. }
  133. }
  134. // 学生得分
  135. if (!$this->error) {
  136. $stuRsArr = $this->sptRsObj->getStudentRsOnePaper($paperId);
  137. if(!$stuRsArr){
  138. $this->errorMsg(0, '没有学生做题数据!');
  139. }
  140. }
  141. if (!$this->error) {
  142. $paperAnalyseArr = $this->paperAnalyse($topicNoArr,$stuRsArr,$needStudentArr,$topicScoreArr,$changeDoTopicNoArr);
  143. }
  144. /**************************** 三、知识点掌握情况 ***********************************/
  145. //TODO 题型方法考察情况
  146. if (!$this->error) {
  147. $topicInfoArr = $this->getTopicInfoArr($topicNoArr);
  148. }
  149. // if (!$this->error) {
  150. // $kpsAnalyseArr = $this->kpsAnalyse($topicInfoArr,$topicScoreArr,$topicNoArr,$stuRsArr,$needStudentArr);
  151. // }
  152. /**************************** 客观题得分 ***********************************/
  153. if(!$this->error){
  154. $answerScoreDetail = $this->objectTopicDetail($paperId,$examInfo, $this->paperTopicIds,$topicNoArr);
  155. }
  156. /**************************** 四、试卷讲评 ***********************************/
  157. if (!$this->error) {
  158. $paperCommentsArr = $this->paperComments($needStudentArr,$stuRsArr,$topicScoreArr,$topicInfoArr,$topicNoArr);
  159. }
  160. if(!$this->error){
  161. list($methodAnalyseArr,$methodTopics,$methodOfTopic) = $this->methodAnalyse($topicInfoArr,$paperCommentsArr);
  162. }
  163. /**************************** 四、方法对应题信息 ***********************************/
  164. if(!$this->error){
  165. $methodTopics = $this->getTopicInfoArr($methodTopics,1);
  166. }
  167. /************ 格式化试题*************/
  168. $_topicInfoArr = array();
  169. $_methodTopicArr = array();
  170. $topicCss=$this->getTopicHtmlArr($_topicInfoArr, $topicInfoArr);
  171. $this->getTopicHtmlArr($_methodTopicArr, $methodTopics);
  172. /******************* 方法训练数据 ************/
  173. if(!$this->error){
  174. $methodPractice = array_slice($methodAnalyseArr,0,6);
  175. foreach ($methodPractice as &$item){
  176. if(!empty($item['classic_topic_ids'])){
  177. foreach ($item['classic_topic_ids'] as $topic_id){
  178. $item['classic_topic_ids'][$topic_id] = isset($_methodTopicArr[$topic_id])?$_methodTopicArr[$topic_id]:array();
  179. }
  180. self::arrayM_desc_sort($item['classic_topic_ids'], 'difficulty_degree');
  181. }
  182. }
  183. }
  184. /**************************** 五、共性题 ***********************************/
  185. if(!$this->error){
  186. $commonTopics = $this->commonTopic($topicNoArr);
  187. if(empty($commonTopics)){
  188. $this->errorMsg(0, '共性题未生成!');
  189. }
  190. }
  191. /************ 同学优解*************/
  192. if(!$this->error){
  193. $besetAnswer = $this->bestAnswer($examInfo,$paperId,$this->controllerObj->schoolGroupId,$is_qxk_page);
  194. }
  195. /**************************** 生产HTML和PDF ***********************************/
  196. if (!$this->error) {
  197. //学生名称
  198. $stuInfoObj = new SStudentInfo();
  199. $stuNameArr = $stuInfoObj->getStudentNames(array_keys($needStudentArr));
  200. $classObj = new SClass();
  201. $className = $classObj->getClassName($this->classId);
  202. $data = array();
  203. $data['className'] = $className;
  204. $data['examInfo'] = $examInfo;
  205. $data['stuNameArr'] = $stuNameArr;
  206. $data['classAnalyseArr'] = $classAnalyseArr;
  207. $data['largeOrderArr'] = $largeOrderArr;
  208. $data['paperAnalyseArr'] = $paperAnalyseArr;
  209. $data['paperCommentsArr'] = $paperCommentsArr;
  210. $data['topicInfoArr'] = $_topicInfoArr;
  211. $data['stuNameArr'] = $stuNameArr;
  212. $data['methodAnalyseArr'] = $methodAnalyseArr;
  213. $data['commonTopics'] = $commonTopics;
  214. $data['answer_score_details'] = $answerScoreDetail;
  215. $data['methodTopicArr'] = $_methodTopicArr;
  216. $data['methodOfTopic'] = $methodOfTopic;
  217. $data['excellent_solution'] = $besetAnswer;
  218. $data['methodPractice'] = $methodPractice;
  219. $data['zsyas2Url'] = $this->getDomain();
  220. $data['topicCss'] = $topicCss;
  221. $html = $this->controllerObj->renderPartial("/productexam/teach_method", $data, true);
  222. // if (is_cli()) {
  223. // $html = $this->controllerObj->viewRender("teach_physics", $data, true);
  224. // }else{
  225. // if ($viewHtml) {
  226. // $this->controllerObj->renderPartial("teaching/teach_physics",$data);exit();
  227. // }else{
  228. // $html = $this->controllerObj->renderPartial("teaching/teach_physics", $data, true);
  229. // }
  230. // }
  231. unset($data);
  232. $actionRs = $this->htmlToPdf($res,$html,$className,$examInfo['exam_name']);
  233. if ($actionRs) {
  234. list($pdfurl, $pdfpath) = $actionRs;
  235. }
  236. }
  237. }
  238. if(!(isset($pdfurl) && $pdfurl && fileGetContents($pdfurl))){
  239. $this->error[] = '文件尚未生成!!'.(!empty($res)?',错误信息:'.json_encode($res):'');
  240. }
  241. $result = array(
  242. 'status' => 1,
  243. 'error' => '',
  244. 'is_create' => 0,
  245. 'pdf_url' => '',
  246. 'pdf_path' => '',
  247. 'file_name' => sprintf("%s_%s_方法宝教学宝",$examInfo['exam_name'],$examInfo['class_name'])
  248. );
  249. if (!$this->error) {
  250. $result['status'] = 0;
  251. $result['is_create'] = 1;
  252. $result['pdf_url'] = $pdfurl;
  253. $result['pdf_path'] = $pdfpath;
  254. }else{
  255. $result['error'] = implode(',',$this->error);
  256. }
  257. return $result;
  258. }
  259. /**
  260. * @param $topicInfoArr
  261. * @param $topicDetailArr
  262. * @return string
  263. */
  264. protected function getTopicHtmlArr(&$topicInfoArr, &$topicDetailArr)
  265. {
  266. $topicHtmlObj = new \TopicHtml\TopicArr\TopicHtmlArr();
  267. $topicHtmlObj->setIsShowAnswerParse(false);
  268. $topicCssObj = new \TopicHtml\TopicArr\TopicCss();
  269. $topicCssObj->setTopicFontSize('7.5pt');
  270. //选择题题干和选项是否分离
  271. $topicCss = $topicCssObj->getTopicCss();
  272. foreach ($topicDetailArr as $topic_id => $topicInfo) {
  273. $topicInfoArr[$topic_id] = $topicHtmlObj->getTopicHtmlArr($topicInfo);
  274. unset($topicInfo);
  275. }
  276. if (!$topicCss) {
  277. $this->errorMsg(0, '获取试题样式失败');
  278. return '';
  279. }
  280. return $topicCss;
  281. }
  282. /**
  283. * 当前考试需要的数据
  284. * @param $examObj
  285. * @param $examInfo
  286. * @param $sprObj
  287. * @param $paperObj
  288. */
  289. private function curExamNeedData(&$sprObj,&$paperObj)
  290. {
  291. $error = array();
  292. $examId = $this->examId;
  293. //试卷关联学生
  294. $sprInfoArr = $sprObj->getStudentExamInfo(array($examId));
  295. if(!$sprInfoArr){
  296. $error[] = '考试没有学生数据!';
  297. }
  298. if (!$error) {
  299. $examStuScore = array();//考试关联学生得分
  300. $absentStu = array();//缺考学生
  301. $paperId = 0;
  302. foreach($sprInfoArr as $key => $value){
  303. $studentId = $value['student_id'];
  304. $paperId = $value['paper_id'];
  305. $examStuScore[$studentId] = $value['scoring'];
  306. if(empty($value['is_feedback'])) {
  307. $absentStu[$studentId] = $value['student_id'];
  308. }
  309. unset($sprInfoArr[$key]);
  310. }
  311. unset($sprInfoArr);
  312. //试卷总分
  313. $paperScore = $paperObj->getPaperScore(array($paperId));
  314. if(!$paperScore){
  315. $error[] = '试卷总分不正确!';
  316. }
  317. if (!$examStuScore) {
  318. $error[] = '没有当前班级数据!';
  319. }
  320. }
  321. if ($error) {
  322. $this->errorMsg(0, implode(',', $error));
  323. return false;
  324. }else{
  325. return array($paperId,$paperScore, $examStuScore,$absentStu);
  326. }
  327. }
  328. /**
  329. * 上次考试需要的数据
  330. * @param $examInfo
  331. * @param $examObj
  332. * @param $sprObj
  333. * @param $paperObj
  334. * @return array|boolean
  335. */
  336. private function preExamNeedData($examInfo,$sprObj,$paperObj)
  337. {
  338. $error = array();
  339. //$examId = $this->examId;
  340. //获取当前考试的上一次考试数据
  341. //$cepObj = new SClassExamPrinter();
  342. //$preInfo = $cepObj->getPreExamId($examId,$examInfo['subject_id'],$examInfo['class_id']);
  343. if(in_array($examInfo['subject_id'], Yii::app()->params['mathSubjectId']))
  344. {
  345. $subjectCondition = ' e.subject_id in ('.implode(',',Yii::app()->params['mathSubjectId']).')';
  346. }else
  347. {
  348. $subjectCondition = ' e.subject_id = '.$examInfo['subject_id'];
  349. }
  350. $sql = "SELECT e.exam_id, p.paper_id
  351. FROM exam e
  352. JOIN paper p ON p.exam_id = e.exam_id
  353. WHERE {$subjectCondition} and e.class_id = '" . $examInfo['class_id'] . "' AND e.complete_time < '" . $examInfo['complete_time'] . "' AND e.status = '1'
  354. ORDER BY e.create_time DESC
  355. LIMIT 1";
  356. $preInfo = $this->getSchoolDbObj()->createCommand($sql)->queryRow();
  357. $preExamId = isset($preInfo['exam_id'])?$preInfo['exam_id']:'';
  358. $prePaperScore = 0;
  359. $examRelPaper = array();
  360. $preExamStuScore = array();//考试关联学生得分
  361. $preAbsent = array();
  362. if($preExamId){
  363. $sprInfoArr = $sprObj->getStudentExamInfo(array($preExamId));
  364. if(!$sprInfoArr){
  365. $error[] = '考试没有关联学生数据!';
  366. }
  367. if (!$error) {
  368. foreach($sprInfoArr as $key => $value){
  369. if(empty($value['is_feedback'])) {
  370. $preAbsent[$value['student_id']] = $value['student_id'];
  371. }
  372. $studentId = $value['student_id'];
  373. $examRelPaper[$value['exam_id']] = $value['paper_id'];
  374. $preExamStuScore[$studentId] = $value['scoring'];
  375. unset($sprInfoArr[$key]);
  376. }
  377. unset($sprInfoArr);
  378. if($examRelPaper){
  379. $prePaperScore = $paperObj->getPaperScore(array_values($examRelPaper));
  380. }
  381. if(!$prePaperScore){
  382. $error[] = '试卷总分不正确!';
  383. }
  384. }
  385. }
  386. if ($error) {
  387. $this->errorMsg(0, implode(',', $error));
  388. return false;
  389. }else{
  390. return array($prePaperScore, $preExamStuScore,$preAbsent);
  391. }
  392. }
  393. /**
  394. * 班级排名得分率人数等数据
  395. * @param $paperScore
  396. * @param $examStuScore
  397. * @return array
  398. */
  399. private function getClassAnalyse($paperScore,&$examStuScore,$prePaperScore, &$preExamStuScore, $absentStu, $preAbsent)
  400. {
  401. $error = array();
  402. $classAnalyArr = array(
  403. 'exam_stu_num' => 0,//参加考试人数
  404. 'miss_stu_num' => 0,//缺考考人数
  405. 'avg_score_rate' => 0,//学生平均得分率
  406. 'pre_avg_rate_diff' => 0,//较上次考试平均得分率上升或下降
  407. 'avg_scoring' => 0,//学生平均分
  408. 'max_scoring' => 0,//最高分
  409. 'min_scoring' => 0,//最低分
  410. 'full_scoring' => 0,//满分
  411. 'pass_rate' => 0,//及格率
  412. 'pass_rate_gt_90' => 0,//其中得分率90%以上的有x人
  413. );
  414. $passStuNum = 0;//及格人数
  415. $classAnalyArr['miss_stu_num'] = count($absentStu); //缺考人数
  416. foreach ($examStuScore as $stuId => $stuScoring) {
  417. if (!isset($absentStu[$stuId])) {
  418. $classAnalyArr['exam_stu_num']++;
  419. }
  420. if ($stuScoring > $classAnalyArr['max_scoring']) {
  421. $classAnalyArr['max_scoring'] = $stuScoring;
  422. }
  423. if(!isset($absentStu[$stuId])){
  424. if ($classAnalyArr['min_scoring'] == 0) {
  425. $classAnalyArr['min_scoring'] = $stuScoring;
  426. }
  427. if ($stuScoring < $classAnalyArr['min_scoring']) {
  428. $classAnalyArr['min_scoring'] = $stuScoring;
  429. }
  430. }
  431. $scoring_rate = ($stuScoring / $paperScore) * 100;
  432. if ($scoring_rate >= 60) {
  433. $passStuNum++;
  434. }
  435. if ($scoring_rate > 90) {
  436. $classAnalyArr['pass_rate_gt_90']++;
  437. }
  438. }
  439. if (!$classAnalyArr['exam_stu_num']) {
  440. $error[] = '班级没有得分大于0的学生!';
  441. }
  442. if (!$error) {
  443. $classAnalyArr['pass_rate'] = number_format($passStuNum / $classAnalyArr['exam_stu_num'], 4) * 100;
  444. $classAnalyArr['full_scoring'] = $paperScore;
  445. $classAnalyArr['avg_score_rate'] = number_format(array_sum($examStuScore) / ($classAnalyArr['exam_stu_num'] * $paperScore), 4) * 100;
  446. $classAnalyArr['avg_scoring'] = number_format(array_sum($examStuScore) / $classAnalyArr['exam_stu_num'], 1);
  447. //上一次班级平均得分率
  448. if ($preExamStuScore) {
  449. $preExamStuNum = 0;//上次参加考试人数
  450. foreach ($preExamStuScore as $stuId => $stuScoring) {
  451. if (!isset($preAbsent[$stuId])) {
  452. $preExamStuNum++;
  453. }
  454. }
  455. //上次平均得分率
  456. if ($preExamStuNum) {
  457. $preAvgScoreRate = number_format(array_sum($preExamStuScore) / ($preExamStuNum * $prePaperScore), 4) * 100;
  458. }else{
  459. $preAvgScoreRate = 0;
  460. }
  461. $classAnalyArr['pre_avg_rate_diff'] = $classAnalyArr['avg_score_rate'] - $preAvgScoreRate;
  462. }
  463. }
  464. if ($error) {
  465. $this->errorMsg(0, implode(',', $error));
  466. return false;
  467. }else{
  468. return $classAnalyArr;
  469. }
  470. }
  471. /**
  472. * 考试分析,大幅进步,大幅退步,前5名和后5名
  473. * @param $examStuScore
  474. * @param $preExamStuScore
  475. * @param $absentStu
  476. * @param $preAbsent
  477. * @return array
  478. */
  479. private function getLargeOrder($examStuScore,$preExamStuScore,$absentStu, $preAbsent){
  480. $largeOrderArr = array(
  481. 'font_five' => array(),//班级前五名
  482. 'back_five' => array(),//班级后五名
  483. 'stu_diff_order' => array(),//名次提升或下降
  484. 'stu_order' => array(),//学生名次
  485. 'increase_stu' => array(),//大幅进步五名
  486. 'reduce_stu' => array(),//大幅退步五名
  487. );
  488. //得分数组(得分>0)
  489. $scoringArr = array();
  490. $needStudentArr = array();//得分大于0的学生
  491. foreach ($examStuScore as $stuId => $stuScoring) {
  492. if (!isset($absentStu[$stuId])) {
  493. $scoringArr[] = $stuScoring;
  494. $needStudentArr[$stuId] = $stuId;
  495. }
  496. }
  497. //学生排名
  498. $stuOrderArr = array();
  499. foreach($examStuScore as $stuId => $stuScoring){
  500. if(!isset($absentStu[$stuId])){
  501. $stuOrderArr[$stuId] = $this->getOrder($stuScoring,$scoringArr);
  502. }
  503. }
  504. if($stuOrderArr){
  505. asort($stuOrderArr);
  506. }
  507. //$diffNum = ceil(count($stuOrderArr)*0.2);
  508. $diffNum = 1;
  509. //班级前五名
  510. //前5名和后5名
  511. $font5 = $back5 = array();
  512. $i = 1;
  513. foreach($stuOrderArr as $stuId => $order){
  514. if($i <= 5){
  515. $font5[$stuId] = $order;
  516. }else{
  517. break;
  518. }
  519. $i++;
  520. }
  521. $largeOrderArr['font_five'] = $font5;
  522. $i = 1;
  523. //删除前5排名
  524. // $_stuOrderArr = $stuOrderArr;
  525. // foreach($_stuOrderArr as $k => $order){
  526. // if(isset($font5[$k])){
  527. // unset($_stuOrderArr[$k]);
  528. // }
  529. // }
  530. arsort($stuOrderArr);
  531. foreach($stuOrderArr as $stuId => $order){
  532. if($i <= 5){
  533. $back5[$stuId] = $order;
  534. }else{
  535. break;
  536. }
  537. $i++;
  538. }
  539. $largeOrderArr['back_five'] = $back5;
  540. /////大幅进步,退步
  541. //上次得分数组(>0)
  542. $preScoringArr = array();
  543. foreach ($preExamStuScore as $stuId => $stuScoring) {
  544. if (!isset($preAbsent[$stuId])) {
  545. $preScoringArr[] = $stuScoring;
  546. }
  547. }
  548. //上次考试学生排名
  549. $preStuOrderArr = array();
  550. foreach($preExamStuScore as $stuId => $stuScoring){
  551. if(isset($preAbsent[$stuId])) continue;
  552. $preStuOrderArr[$stuId] = $this->getOrder($stuScoring,$preScoringArr);
  553. }
  554. if($preStuOrderArr){
  555. asort($preStuOrderArr);
  556. }
  557. if($preStuOrderArr){
  558. $interOrderArr = array_intersect_key($stuOrderArr,$preStuOrderArr);
  559. if(!$interOrderArr){
  560. $interOrderArr = $stuOrderArr;
  561. }
  562. }else{
  563. $interOrderArr = array();
  564. }
  565. $increaseArr = $reduceArr = array();
  566. $stuDiffOrder = array();
  567. if($interOrderArr){
  568. foreach($stuOrderArr as $stuId => $order){
  569. if(isset($interOrderArr[$stuId]) && isset($preStuOrderArr[$stuId])){
  570. $stuDiffOrder[$stuId] = -($order - $preStuOrderArr[$stuId]);
  571. }else{
  572. $stuDiffOrder[$stuId] = 0;
  573. }
  574. }
  575. arsort($stuDiffOrder);
  576. foreach($stuDiffOrder as $stuId => $num){
  577. if($num >= $diffNum){
  578. $increaseArr[] = $stuId;
  579. }
  580. }
  581. $increaseArr = array_slice($increaseArr,0,5,true);
  582. asort($stuDiffOrder);
  583. foreach($stuDiffOrder as $stuId => $num){
  584. if($num <= -$diffNum){
  585. $reduceArr[] = $stuId;
  586. }
  587. }
  588. $reduceArr = array_slice($reduceArr,0,5,true);
  589. }else{
  590. $increaseArr = array_slice($stuOrderArr,0,5,true);
  591. $reduceArr = array();
  592. }
  593. $largeOrderArr['stu_diff_order'] = $stuDiffOrder;
  594. $largeOrderArr['stu_order'] = $stuOrderArr;
  595. $largeOrderArr['increase_stu'] = $increaseArr;
  596. $largeOrderArr['reduce_stu'] = $reduceArr;
  597. return array($largeOrderArr,$needStudentArr);
  598. }
  599. /**
  600. * 获取排名
  601. * @param $ele
  602. * @param $arr
  603. * @return false|int|string
  604. */
  605. private function getOrder($ele,$arr){
  606. $orderRs = 0;
  607. if($arr){
  608. arsort($arr);
  609. $arr = array_values($arr);
  610. $index = array_search($ele,$arr);
  611. $orderRs = $index + 1;
  612. }
  613. return $orderRs;
  614. }
  615. /**
  616. * 试卷情况分析
  617. * @param $topicNoArr
  618. * @param $stuRsArr
  619. * @param $needStudentArr
  620. * @param $topicScoreArr
  621. * @param $changeDoTopicNoArr
  622. * @return array
  623. */
  624. private function paperAnalyse(&$topicNoArr,&$stuRsArr,$needStudentArr,$topicScoreArr,&$changeDoTopicNoArr)
  625. {
  626. //$changeTopicStuNum选做题实际做题人数
  627. $changeTopicStuNum = $paperAnalyseArr = array();
  628. $topicWrongNumArr = array();//题答错人数
  629. $hasRsTopicIds = array(); //参与作答的题
  630. foreach ($needStudentArr as $stuId) {
  631. if(!(isset($stuRsArr[$stuId])) && $stuRsArr[$stuId]) continue;
  632. foreach ($stuRsArr[$stuId] as $topicId => $rs) {
  633. if (!isset($topicWrongNumArr[$topicId])) {
  634. $topicWrongNumArr[$topicId] = 0;
  635. }
  636. if ($rs['scoring'] < $topicScoreArr[$topicId]) {
  637. $topicWrongNumArr[$topicId]++;
  638. }
  639. $hasRsTopicIds[$topicId] = $topicId;
  640. if(!empty($changeDoTopicNoArr) && isset($changeDoTopicNoArr["list"][$topicId])){//选做题实际做题人数
  641. if (!isset($changeTopicStuNum[$topicId])) {
  642. $changeTopicStuNum[$topicId] = 0;
  643. }
  644. $changeTopicStuNum[$topicId] ++;
  645. }
  646. }
  647. }
  648. $stuTotalNum = count($needStudentArr);//学生总人数
  649. foreach ($topicNoArr as $topicId => $no) {
  650. if(isset($hasRsTopicIds[$topicId])) {
  651. $wrongNum = isset($topicWrongNumArr[$topicId]) ? $topicWrongNumArr[$topicId] : 0;
  652. if(!empty($changeDoTopicNoArr) && isset($changeDoTopicNoArr["list"][$topicId]) && isset($changeTopicStuNum[$topicId])){
  653. $countStuTotalNum = $changeTopicStuNum[$topicId];//选做题实际做题人数
  654. }else{
  655. $countStuTotalNum = $stuTotalNum;//正常题目的人数
  656. }
  657. $paperAnalyseArr[] = array(
  658. 'no' => $no,
  659. 'wrong_num' => $wrongNum,
  660. 'wrong_rate' => number_format($wrongNum / $countStuTotalNum, 4) * 100,
  661. );
  662. }else{
  663. unset($topicNoArr[$topicId]);
  664. }
  665. }
  666. return $paperAnalyseArr;
  667. }
  668. /**
  669. * 获取题内容
  670. * @param $topicNoArr
  671. * @param $isMissing 是否允许缺题 1允许0不允许
  672. * @return array|false
  673. */
  674. private function getTopicInfoArr($topicNoArr,$isMissing=0)
  675. {
  676. $error = array();
  677. $topicIds = array_keys($topicNoArr);
  678. $topicDetails = array();
  679. $topics = $this->apiBrainPost('/topic/batchAll', array('topicIds' => $topicIds,'subjectId' => $this->subjectId,'params'=>array('isFormat'=>0,'isThird'=>1)),25,true);
  680. if(!$topics|| !is_array($topics)){
  681. $this->errorMsg(0, "试题内容获取失败!");
  682. return false;
  683. }
  684. foreach ($topics as $topic){
  685. $topicDetails[number_format($topic['id'], 0, '', '')] = $topic;
  686. }
  687. if (!$error) {
  688. $diff_id_arr = array();
  689. foreach ($topicNoArr as $topicId => $v) {
  690. if (!isset($topicDetails[$topicId])) {
  691. $diff_id_arr[] = $topicId;
  692. }
  693. }
  694. if (!empty($diff_id_arr)) {
  695. $error[] = "没有试题内容!(" . implode(',', $diff_id_arr) . ")";
  696. }
  697. }
  698. if ($error && $isMissing==0) {
  699. $this->errorMsg(0, implode(',', $error));
  700. return false;
  701. }else{
  702. return $topicDetails;
  703. }
  704. }
  705. /**
  706. * 题型方法掌握情况
  707. * @param $topicInfoArr
  708. * @param $paperCommentsArr
  709. * @return array
  710. */
  711. public function methodAnalyse(&$topicInfoArr,$paperCommentsArr)
  712. {
  713. $topicArr = array();
  714. foreach ($paperCommentsArr as $item){
  715. $topicArr[$item['topic_id']] = $item;
  716. }
  717. //题型方法对应题
  718. list($methodsTopics,$methodOfTopic) = $this->methodTopics($topicInfoArr);
  719. //题型方法信息
  720. $topics = array();
  721. if($methodsTopics) {
  722. list($methodInfos, $topics) = $this->methodInfos(array_keys($methodsTopics));
  723. }
  724. //题型方法得分率
  725. foreach ($methodsTopics as $methodId=>$methodsTopic){
  726. $own = 0;
  727. $full = 0;
  728. foreach ($methodsTopic as $methodTopicId){
  729. $own += $topicArr[$methodTopicId]['stu_score_total'];
  730. $full += $topicArr[$methodTopicId]['topic_score_total'];
  731. if(isset($topicArr[$methodTopicId])) {
  732. $methodInfos[$methodId]['topicRs'][$methodTopicId] = $topicArr[$methodTopicId];
  733. }
  734. }
  735. //$methodInfos[$methodId]['rate'] = $full ? number_format($own/$full,4)*100 : 0;
  736. $methodInfos[$methodId]['rate'] = $full ? number_format(($own/$full)*100, 2) : 0;
  737. $methodInfos[$methodId]['star'] = $this->getStarNum($methodInfos[$methodId]['rate']);
  738. $methodInfos[$methodId]['methodId'] = $methodId;
  739. }
  740. $methodAnalyse = array();
  741. if($methodInfos){
  742. arrayMsort($methodInfos, 'rate');
  743. foreach ($methodInfos as $methodInfo){
  744. $methodAnalyse[$methodInfo['methodId']] = $methodInfo;
  745. }
  746. }
  747. return array($methodAnalyse,$topics,$methodOfTopic);
  748. }
  749. /**
  750. * 试卷讲评
  751. * @param $needStudentArr
  752. * @param $stuRsArr
  753. * @param $topicScoreArr
  754. * @param $topicInfoArr
  755. * @param $topicNoArr
  756. * @return array
  757. */
  758. private function paperComments(&$needStudentArr,&$stuRsArr,$topicScoreArr,&$topicInfoArr,$topicNoArr)
  759. {
  760. $paperCommentsArr = array();
  761. // $_paperCommentsArr = array(
  762. // 'topic_no' => 0,//试题序号
  763. // 'class_scoring_rate' => 0,//班级得分率
  764. // 'grade_scoring_rate' => 0,//年级得分率
  765. // 'wrong_stu_arr' => 0,//答错学生
  766. // 'right_stu_num' => 0,//答对学生数
  767. // 'push_topic_id' => 0,//推送题ID
  768. // );
  769. //试题对应的所有学生得分
  770. $topicScoringArr = array();//试题得分
  771. $topicTotalScoreArr = array();//试题总分
  772. $wrongStuArr = array();//答错学生
  773. $rightStuNumArr = array();//答对学生数
  774. foreach ($stuRsArr as $stuId => $stuTopicRs) {
  775. foreach ($stuTopicRs as $topicId => $stuRs) {
  776. if(!isset($needStudentArr[$stuId])) continue;
  777. if (!isset($topicScoringArr[$topicId])) {
  778. $topicScoringArr[$topicId] = 0;
  779. }
  780. $topicScoringArr[$topicId] += $stuRs['scoring'];
  781. if (!isset($topicTotalScoreArr[$topicId])) {
  782. $topicTotalScoreArr[$topicId] = 0;
  783. }
  784. $topicTotalScoreArr[$topicId] += isset($topicScoreArr[$topicId]) ? $topicScoreArr[$topicId] : 0;
  785. //答错学生
  786. if ($stuRs['scoring'] == $topicScoreArr[$topicId]) {
  787. if (!isset($rightStuNumArr[$topicId])) {
  788. $rightStuNumArr[$topicId] = 0;
  789. }
  790. $rightStuNumArr[$topicId]++;
  791. }else{
  792. if (!isset($wrongStuArr[$topicId])) {
  793. $wrongStuArr[$topicId] = array();
  794. }
  795. $wrongStuArr[$topicId][$stuId] = $stuId;
  796. }
  797. }
  798. }
  799. //班级得分率
  800. $classScoringRateArr = array();
  801. foreach ($topicScoringArr as $topicId => $scoring) {
  802. $classScoringRateArr[$topicId] = $this->numberFormat($scoring / $topicTotalScoreArr[$topicId], 2) * 100;
  803. }
  804. //年级得分率
  805. //$gradeScoringRateArr = $this->getGradeScoringRate($topicScoreArr);
  806. foreach ($topicNoArr as $topicId => $topicNo) {
  807. $_wrongStuArr = isset($wrongStuArr[$topicId]) ? $wrongStuArr[$topicId] : array();
  808. $paperCommentsArr[$topicId] = array(
  809. 'topic_id' => $topicId,
  810. 'topic_no' => $topicNo,
  811. 'class_scoring_rate' => isset($classScoringRateArr[$topicId])?$classScoringRateArr[$topicId]:0,
  812. //'grade_scoring_rate' => isset($gradeScoringRateArr[$topicId])?$gradeScoringRateArr[$topicId]:0,
  813. 'wrong_stu_arr' => array_keys($_wrongStuArr),
  814. 'wrong_stu_num' => count($_wrongStuArr),
  815. 'right_stu_num' => isset($rightStuNumArr[$topicId])?$rightStuNumArr[$topicId]:0,
  816. 'stu_score_total' => isset($topicScoringArr[$topicId]) ? $topicScoringArr[$topicId] : 0,
  817. 'topic_score_total' => isset($topicTotalScoreArr[$topicId]) ? $topicTotalScoreArr[$topicId] : 0
  818. );
  819. }
  820. return $paperCommentsArr;
  821. }
  822. /**
  823. * 年级得分率
  824. * @param $topicScoreArr 试题分数
  825. * @param $topicScoringArr 试题得分(初始值是班级得分)
  826. * @param $topicTotalScoreArr 试题总分分(初始值是班级总分)
  827. * @return array
  828. */
  829. private function getGradeScoringRate($topicScoreArr)
  830. {
  831. $gradeScoringRateArr = array();
  832. $examIds = $this->examObj->getExamIds($this->examGroupId);
  833. $needStuArr = array();//得分大于0的学生
  834. $paperIds = array();
  835. if($examIds){
  836. //试卷关联学生
  837. $sprInfoArr = $this->sprObj->getStudentExamInfo($examIds);
  838. if ($sprInfoArr) {
  839. foreach ($sprInfoArr as $sprInfo) {
  840. if ($sprInfo['scoring'] > 0) {
  841. $needStuArr[$sprInfo['student_id']] = $sprInfo['student_id'];
  842. $paperIds[$sprInfo['paper_id']] = $sprInfo['paper_id'];
  843. }
  844. }
  845. }
  846. unset($sprInfoArr);
  847. }
  848. $topicScoringArr = array();
  849. $topicTotalScoreArr = array();
  850. if ($paperIds) {
  851. foreach ($paperIds as $paperId) {
  852. $_stuRsArr = $this->sptRsObj->getStudentRsOnePaper($paperId);
  853. if(!$_stuRsArr){
  854. continue;
  855. }
  856. foreach ($_stuRsArr as $stuId => $stuTopicRs) {
  857. foreach ($stuTopicRs as $topicId => $stuRs) {
  858. if(!isset($needStuArr[$stuId])) continue;
  859. if (!isset($topicScoringArr[$topicId])) {
  860. $topicScoringArr[$topicId] = 0;
  861. }
  862. $topicScoringArr[$topicId] += $stuRs['scoring'];
  863. if (!isset($topicTotalScoreArr[$topicId])) {
  864. $topicTotalScoreArr[$topicId] = 0;
  865. }
  866. $topicTotalScoreArr[$topicId] += isset($topicScoreArr[$topicId]) ? $topicScoreArr[$topicId] : 0;
  867. }
  868. unset($stuTopicRs);
  869. }
  870. unset($_stuRsArr);
  871. }
  872. }
  873. //年级得分率
  874. foreach ($topicScoringArr as $topicId => $scoring) {
  875. $gradeScoringRateArr[$topicId] = number_format($scoring / $topicTotalScoreArr[$topicId], 2) * 100;
  876. }
  877. return $gradeScoringRateArr;
  878. }
  879. /**
  880. * hmtl生产PDF
  881. * @param $res
  882. * @param $html
  883. * @param $className
  884. * @param $examName
  885. * @return boolean|array
  886. */
  887. private function htmlToPdf($res,&$html,$className,$examName)
  888. {
  889. $error = array();
  890. $examId = $this->examId;
  891. $htmlpath = str_replace("protected", "", Yii::app()->basePath) . '/upload/tmpDir/academicr/'; //存放生成的HTML路径
  892. $pdfpath = str_replace("protected", "", Yii::app()->basePath) . '/upload/tmpDir/academicr/' . $this->schoolId . "/"; //存放生成的PDF路径
  893. $pdfurl = '/upload/tmpDir/academicr/' . $this->schoolId . "/";
  894. if (!is_dir($htmlpath)) {
  895. if (!mkdir($htmlpath, 0777, true)) {
  896. $error[] = 'Create directory fail: ' . $htmlpath;
  897. }
  898. }
  899. if (!is_dir($pdfpath)) {
  900. if (!mkdir($pdfpath, 0777, true)) {
  901. $error[] = 'Create directory fail: ' . $pdfpath;
  902. }
  903. }
  904. if (!$error) {
  905. $locale='en_US.UTF-8'; // 或 $locale='zh_CN.UTF-8';
  906. setlocale(LC_ALL,$locale);
  907. putenv('LC_ALL='.$locale);
  908. $htmlpath .= $examId . '-'. $this->productType . ".html";
  909. $f = fopen($htmlpath, "w");
  910. fwrite($f, $html);
  911. fclose($f);
  912. $htmlurl = '/upload/tmpDir/academicr/' . $examId. '-'. $this->productType . ".html"; //访问HTML的路径
  913. $server = Yii::app()->params['phantomjs_server'];
  914. $js = 'html2pdf_math.js';
  915. $htmlurl = $this->getDomain() . $htmlurl;
  916. $pdffname = $this->classId . "-" . $examId . "-". $this->productType .".pdf";
  917. $pdfpath = $pdfpath . $pdffname;
  918. $pdfurl = $pdfurl . $pdffname;
  919. $schoolInfo = $this->controllerObj->schoolInfo;
  920. $schoolName = isset($schoolInfo['school_name'])?$schoolInfo['school_name']:'';
  921. $commond = $server . " "
  922. . Yii::app()->basePath . '/../js/'.$js . " "
  923. . " {$htmlurl}"
  924. . " {$pdfpath}"
  925. . " 176mm*250mm '{$schoolName} {$className}+++ +++时间:".date('Y-m-d')." 教学宝'";
  926. exec($commond, $res, $code);
  927. }
  928. if(isset($res) && isset($res[0])){
  929. $isBool = false;
  930. foreach($res as $msg){
  931. if (strpos($msg, 'succeed') !== false){
  932. $isBool = true;
  933. }
  934. }
  935. if ($isBool) {//命令返回成功
  936. if (file_exists($pdfpath)) {
  937. // $pdfurl=iconv("GBK", "UTF-8",$pdfurl);
  938. $repdf = $examId . ".pdf";
  939. $rename = 'zsyas2/academicr/'.$this->schoolId.'/'. date('Y') . '/' . date('m') . '/' . date('d').'/'. uniqid() . '.' . $repdf;
  940. $ucloud = new Qcloud();
  941. $uploadInfo = $ucloud->putFile($rename, $pdfpath);
  942. if ($uploadInfo['status'] == 0) {
  943. $pdfurl = $this->getDomain() . $pdfurl;
  944. $this->getSchoolDbObj()->createCommand()->update("exam_teaching_product", array("is_create_html"=>1,"html_path"=>$htmlpath,"pdf_path" => $pdfurl, "pdf_create_time" => time(), "is_create_pdf" => 1), "exam_id = '{$examId}' and product_type={$this->productType}");
  945. }else{
  946. $pdfurl = $uploadInfo['url'];
  947. $this->getSchoolDbObj()->createCommand()->update("exam_teaching_product", array("is_create_html"=>1,"html_path"=>$htmlpath,"pdf_path" => $pdfurl, "pdf_create_time" => time(), "is_create_pdf" => 1), "exam_id = '{$examId}' and product_type={$this->productType}");
  948. //批量生产不生产PDF
  949. if (!is_cli()) {
  950. @unlink($pdfpath);
  951. }
  952. }
  953. @unlink($htmlpath);
  954. } else {
  955. $this->getSchoolDbObj()->createCommand()->update("exam_teaching_product", array("pdf_path" => "", "pdf_create_time" => 0, "is_create_pdf" => 0), "exam_id = '{$examId}' and product_type={$this->productType}");
  956. @unlink($htmlpath);
  957. $error[] = 'PDF文件未找到! ';
  958. }
  959. } else {
  960. @unlink($htmlpath);
  961. $error[] = 'PDF创建失败!,错误信息:(' . json_encode($res) . ') ';
  962. }
  963. }else{
  964. Curl::post(Yii::app()->params['handle_log_api'], array(
  965. "exam_group_id" => (string)$this->examGroupId,
  966. "operate_project" => 'zsyas2',
  967. "school_id" => $this->schoolId,
  968. "title" => '下载教师讲案',
  969. "operate_account" => is_cli()?'':Yii::app()->session['coachInfo']['coach_name'],
  970. "operate_method" => $this->controllerObj->action,
  971. "operate_url" => $this->controllerObj->getRoute(),
  972. "operate_sql" => '',
  973. "operate_param" =>json_encode(array('post'=>array("examId"=>$examId,"pdf"=>array("commond"=>$commond,"res"=>$res,"code"=>$code),"htmlurl"=>''))),
  974. ));
  975. $error[] = 'PDF创建失败! ';
  976. }
  977. if ($error) {
  978. $this->errorMsg(0, implode(',', $error));
  979. return false;
  980. }else{
  981. return array($pdfurl,$pdfpath);
  982. }
  983. }
  984. /**
  985. * 调题的接口
  986. * @param $path
  987. * @param $arr
  988. * @param int $type
  989. * @return bool|mixed
  990. */
  991. public function apiBrainPost($path, $arr, $timeout=25,$is_array = false)
  992. {
  993. $ch = @curl_init();
  994. $result = FALSE;
  995. if ($ch)
  996. {
  997. $data = json_encode($arr);
  998. $url = Yii::app()->params['api'][0]['prefix'] . $path;
  999. $username = Yii::app()->params['api'][0]['username'];
  1000. $password = Yii::app()->params['api'][0]['password'];
  1001. curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
  1002. curl_setopt($ch, CURLOPT_USERPWD, $username . ':' . $password);
  1003. // 不输出头部
  1004. curl_setopt($ch, CURLOPT_HEADER, 0);
  1005. // curl_exec 获取到的内容不直接输出, 而是返回
  1006. curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
  1007. curl_setopt($ch, CURLOPT_TIMEOUT,$timeout);
  1008. // 请求重启路由器的地址 传参 进行重启
  1009. curl_setopt($ch, CURLOPT_URL, $url);
  1010. curl_setopt($ch, CURLOPT_USERAGENT, 'Api Client/1.0.0 (chengfei@liancaitech.com)');
  1011. curl_setopt($ch, CURLOPT_POST, 1);
  1012. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  1013. curl_setopt($ch, CURLOPT_HTTPHEADER, array(
  1014. 'Content-Type: application/json',
  1015. 'Content-Length: '. strlen($data),
  1016. ));
  1017. if( !curl_errno($ch))
  1018. {
  1019. $result = json_decode(curl_exec($ch),$is_array);
  1020. }
  1021. // 释放资源
  1022. curl_close($ch);
  1023. }
  1024. return $result;
  1025. }
  1026. public function getDomain()
  1027. {
  1028. if (is_cli()) {
  1029. return Yii::app()->params['zsyas2_url'];
  1030. }else{
  1031. return Yii::app()->request->hostInfo;
  1032. }
  1033. }
  1034. /**
  1035. * 错误信息
  1036. * @param $status
  1037. * @param $msg
  1038. */
  1039. private function errorMsg($status,$msg)
  1040. {
  1041. $this->error[] = $msg;
  1042. // echo json_encode(array("status" => $status, "error" => $msg));
  1043. // exit;
  1044. }
  1045. /**
  1046. * 学校数据库连接对象
  1047. * @return mixed
  1048. */
  1049. protected function getSchoolDbObj()
  1050. {
  1051. if (is_cli()) {
  1052. return $this->controllerObj->getSchConnObj();
  1053. }else{
  1054. return $this->controllerObj->sConn;
  1055. }
  1056. }
  1057. /**
  1058. * 数组格式化
  1059. * @param $num 小数
  1060. * @param $bat 小数位数
  1061. * @return float|int
  1062. */
  1063. private function numberFormat($num,$bat)
  1064. {
  1065. $pow = pow(10, $bat);
  1066. $num = $num * $pow;
  1067. $num = floor($num) / $pow;
  1068. return $num;
  1069. }
  1070. /**
  1071. * 获取题型方法对应题id集
  1072. * @param $topicInfos
  1073. * @return array
  1074. */
  1075. private function methodTopics($topicInfos){
  1076. $res = array();
  1077. $methodOfTopic = array();
  1078. foreach ($topicInfos as $key=>$topicInfo){
  1079. if(isset($topicInfo['affiliate'])){
  1080. foreach ($topicInfo['affiliate'] as $item){
  1081. if($item['field_key'] == 'tag_3_209' && !empty($item['field_value'])){
  1082. $methodIds = explode('|', $item['field_value']);
  1083. foreach ($methodIds as $methodId){
  1084. $res[$methodId][] = $key;
  1085. $methodOfTopic[$key][] = $methodId;
  1086. }
  1087. break;
  1088. }
  1089. }
  1090. }
  1091. }
  1092. if(empty($res) || empty($methodOfTopic)){
  1093. $error[] = '未获取到题方法数据';
  1094. }
  1095. return array($res,$methodOfTopic);
  1096. }
  1097. /**
  1098. * 获取题型方法信息
  1099. * @param $methodIds
  1100. * @return array|boolean
  1101. */
  1102. private function methodInfos($methodIds){
  1103. $rs = $this->apiBrainPost('/all_content/detail', array('catalogIds' => $methodIds),25,true);
  1104. if(isset($rs['status']) && $rs['status']==1){
  1105. $methodDetails = $rs['data'];
  1106. }else{
  1107. $error[] = '题型方法数据为空! ';
  1108. return false;
  1109. }
  1110. $methods = array();
  1111. $topicIds = array();
  1112. foreach ($methodDetails as $detail){
  1113. if(isset($detail['column_id'])){
  1114. switch ($detail['column_id']){
  1115. case self::FULLTEXT_COLUMN_ID: //方法释义文本
  1116. $methods[$detail['catalog_id']]['name'] = $detail['catalog_name'];
  1117. $methods[$detail['catalog_id']]['content'] = \TopicHtml\Topic\Image::resetImgSizeNoTopic($detail['content']);
  1118. break;
  1119. case self::CLASSIC_COLUMN_ID: //典型例题文本
  1120. $methods[$detail['catalog_id']]['name'] = $detail['catalog_name'];
  1121. $methods[$detail['catalog_id']]['classic_content'] = \TopicHtml\Topic\Image::resetImgSizeNoTopic($detail['content']);
  1122. break;
  1123. case self::SPECIAL_COLUMN_ID: //方法专练
  1124. $methods[$detail['catalog_id']]['name'] = $detail['catalog_name'];
  1125. $methods[$detail['catalog_id']]['classic_topic_ids'][number_format($detail['topic_id'], 0, '', '')] = number_format($detail['topic_id'], 0, '', '');
  1126. $topicIds[number_format($detail['topic_id'], 0, '', '')] = number_format($detail['topic_id'], 0, '', '');
  1127. break;
  1128. default:
  1129. $methods[$detail['catalog_id']]['name'] = $detail['catalog_name'];
  1130. break;
  1131. }
  1132. }
  1133. }
  1134. return array($methods,$topicIds);
  1135. }
  1136. /**
  1137. * 获取共性题数据
  1138. * topicNoArr题号
  1139. * @return array
  1140. */
  1141. private function commonTopic($topicNoArr = array())
  1142. {
  1143. $rs = SProductCommonTopic::model()->getCommonTopic($this->examId);
  1144. if(empty($rs)){
  1145. $error[] = '未生成共性题! ';
  1146. }
  1147. $commonTopics = array();
  1148. foreach ($rs as $item){
  1149. $commonTopics[$item['template_id']]['topic_id'] = $item['template_id'];
  1150. if(isset($topicNoArr[$item['template_id']])){
  1151. $commonTopics[$item['template_id']]['topic_no'] = $topicNoArr[$item['template_id']];
  1152. }else{
  1153. $commonTopics[$item['template_id']]['topic_no'] = $item['template_no'];
  1154. }
  1155. }
  1156. return $commonTopics;
  1157. }
  1158. /**
  1159. * 客观题答题详细
  1160. * @param $paperId
  1161. * @param $examInfo
  1162. * @param $paperTopicIds
  1163. * @param $topicNoArr 题号
  1164. * @return array
  1165. */
  1166. private function objectTopicDetail($paperId, $examInfo, $paperTopicIds,$topicNoArr){
  1167. $answer_score_details = array();
  1168. $query = SPaperTopicRelation::model()->getStudentRs($paperId);
  1169. if ($query) {
  1170. //转换试卷中每道题目的序号
  1171. foreach ($query as $k => $v) {
  1172. $no = isset($topicNoArr[$v["topic_id"]])?$topicNoArr[$v["topic_id"]]:$v["order"];
  1173. //客观题答案明细
  1174. //import_score_type; 1 成绩导入流程 0-正常扫描
  1175. if($v['type'] == 1 && !$examInfo['import_score_type']){//单选题
  1176. if(!isset($answer_score_details[$v['topic_id']])){
  1177. $answer_score_details[$v['topic_id']] = array();
  1178. $answer_score_details[$v['topic_id']]['answer'] = '';
  1179. $answer_score_details[$v['topic_id']]['option']['A'] = 0;
  1180. $answer_score_details[$v['topic_id']]['option']['B'] = 0;
  1181. $answer_score_details[$v['topic_id']]['option']['C'] = 0;
  1182. $answer_score_details[$v['topic_id']]['option']['D'] = 0;
  1183. $answer_score_details[$v['topic_id']]['order'] = $no;
  1184. }
  1185. if(isset($answer_score_details[$v['topic_id']]['option'][$v['answer']])){
  1186. $answer_score_details[$v['topic_id']]['option'][$v['answer']]++;
  1187. }
  1188. }
  1189. if((in_array($v['type'],array(2,11)) && !$examInfo['import_score_type']) || ($examInfo['qxk_paper_id'] && $v['type']==3)){//多选不定项
  1190. $v_answer = str_replace(',','',$v['answer']);
  1191. if(!isset($answer_score_details[$v['topic_id']])){
  1192. $answer_score_details[$v['topic_id']] = array();
  1193. $answer_score_details[$v['topic_id']]['answer'] = '';
  1194. $answer_score_details[$v['topic_id']]['order'] = $no;
  1195. }
  1196. if(isset($answer_score_details[$v['topic_id']]['option'][$v_answer])){
  1197. $answer_score_details[$v['topic_id']]['option'][$v_answer]++;
  1198. }else{
  1199. $answer_score_details[$v['topic_id']]['option'][$v_answer] = 1;
  1200. }
  1201. }
  1202. }
  1203. }
  1204. $topicDetails=array();
  1205. $topicItems_1 = $this->apiBrainPost('/topic/batchAll', array('topicIds' =>$paperTopicIds));
  1206. if (isset($topicItems_1->error)) {
  1207. $error[] = $topicItems_1->error;
  1208. } elseif (! $topicItems_1) {
  1209. $error[] = 'Error in pumping system[2]';
  1210. } else {
  1211. foreach ($topicItems_1 as $topicItem) {
  1212. $topicDetails[$topicItem->id] = (object)$topicItem;
  1213. }
  1214. }
  1215. if ($topicDetails) {
  1216. foreach ($topicDetails as $k => $v) {
  1217. $v=(array)$v;
  1218. $v['id'] = (string)$v['id'];
  1219. if(isset($v['items'][0])){
  1220. $v['items'][0]=(array)$v['items'][0];
  1221. $v['items'][0]['options']=(array)$v['items'][0]['options'];
  1222. if (isset($v['items']) && isset($v['items'][0]) && isset($v['items'][0]['options'])) {
  1223. foreach ($v['items'][0]['options'] as $key => $val) {
  1224. $val=(array)$val;
  1225. if(isset($answer_score_details[$v['id']]) && $val['option_correct'] == 1){
  1226. $answer_score_details[$v['id']]['answer'] .= $this->numToLetter($key + 1);
  1227. }
  1228. }
  1229. }
  1230. }
  1231. }
  1232. }
  1233. $new_answer_score_details = array();
  1234. //整理客观题明细数据
  1235. if($answer_score_details){
  1236. $a = 0;
  1237. foreach($answer_score_details as $k=>$v){
  1238. if(isset($v['option']) && $v['option']){
  1239. foreach($v['option'] as $option_type=>$option_count){
  1240. $new_answer_score_details[$a]['id'] = $k;
  1241. $new_answer_score_details[$a]['order'] = $v['order'];
  1242. $new_answer_score_details[$a]['answer'] = $v['answer']?$v['answer']:'';
  1243. $new_answer_score_details[$a]['option'] = $option_type;
  1244. $new_answer_score_details[$a]['option_count'] = $option_count;
  1245. $a++;
  1246. }
  1247. }
  1248. }
  1249. }
  1250. return $new_answer_score_details;
  1251. }
  1252. public function numToLetter($number) {
  1253. $letters = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z');
  1254. $number = (int) $number;
  1255. $result = '';
  1256. if ($number >= 1 AND $number <= 26) {
  1257. $result = $letters[$number - 1];
  1258. }
  1259. return $result;
  1260. }
  1261. /** 获取方法得分率星级
  1262. * @param $rate
  1263. * @return int
  1264. */
  1265. private function getStarNum($rate)
  1266. {
  1267. if ($rate >= 80 && $rate <= 100) {
  1268. $starNum = 5;
  1269. }elseif($rate >= 60 && $rate < 80){
  1270. $starNum = 4;
  1271. }elseif($rate >= 40 && $rate < 60){
  1272. $starNum = 3;
  1273. }elseif($rate >= 20 && $rate < 40){
  1274. $starNum = 2;
  1275. }else{
  1276. $starNum = 1;
  1277. }
  1278. return $starNum;
  1279. }
  1280. //多维数组降序排序
  1281. static function arrayM_desc_sort(&$data,$field)
  1282. {
  1283. $regions = _array_column($data, $field);
  1284. utf8_array_asort($regions);
  1285. array_multisort($regions, SORT_DESC, $data);
  1286. }
  1287. /**
  1288. * 同学优解
  1289. * @param $examInfo
  1290. * @param $paperId
  1291. * @param $groupId
  1292. * @param $isQxk是否全学科试卷
  1293. * @return array
  1294. * @throws CDbException
  1295. * @throws CException
  1296. */
  1297. public function bestAnswer($examInfo, $paperId, $groupId,$isQxk=0){
  1298. if($isQxk){
  1299. $typeArr =array(8,9);
  1300. }else{
  1301. $typeArr =array(7,17,27);
  1302. }
  1303. //获取考试试题对应优解分数
  1304. $topic_sql = "select topic_id,score from paper_topic_relation where paper_id = '{$paperId}' and type in (".join(",",$typeArr).")";
  1305. $topic_sql_rs = $this->getSchoolDbObj()->createCommand($topic_sql)->queryAll();
  1306. $fine_topic_score = array();
  1307. foreach ($topic_sql_rs as $item){
  1308. $fine_topic_score[$item['topic_id']] = 0.7*$item['score'];
  1309. }
  1310. $static_url_data = Yii::app()->params['static_url'][$groupId];
  1311. //获取同学优解(优先取marking_special_answer 没有再取student_paper_topic_rs)
  1312. $excellent_solution = array();
  1313. $sql = "select paper_id,student_id,sptr_id,topic_id,clazz_id from marking_special_answer where paper_id = '{$paperId}' and type = 2";
  1314. $special_data = $this->getSchoolDbObj()->createCommand($sql)->queryAll();
  1315. if($special_data){
  1316. foreach($special_data as $k=>$v){
  1317. if(!isset($excellent_solution[(string)$v['topic_id']])){
  1318. $temp_class_id = $v["clazz_id"];
  1319. $temp_student_id = $v["student_id"];
  1320. $temp_sptr_id = $v["sptr_id"];
  1321. //获取班级名称
  1322. $sql = "select class_name from class where class_id = '{$temp_class_id}'";
  1323. $class_data = $this->getSchoolDbObj()->createCommand($sql)->queryRow();
  1324. if($class_data){
  1325. $excellent_solution[(string)$v['topic_id']]['class_name'] = $class_data['class_name'];
  1326. }
  1327. //获取学生姓名
  1328. $sql = "select realname from student_info where student_id = '{$temp_student_id}'";
  1329. $student_data = $this->getSchoolDbObj()->createCommand($sql)->queryRow();
  1330. if($student_data){
  1331. $excellent_solution[(string)$v['topic_id']]['student_name'] = $student_data['realname'];
  1332. }
  1333. //获取学生答案
  1334. $sql = "select answer_url from student_paper_topic_rs where id = '{$temp_sptr_id}'";
  1335. // if(empty($codeNow)){
  1336. // $sql = "select answer_url from student_paper_topic_rs where id = '{$temp_sptr_id}'";
  1337. // }else{
  1338. // $sql = "select answer_url from student_paper_topic_rs_".$codeNow." where id = '{$temp_sptr_id}'";
  1339. // }
  1340. $sptr_data = $this->getSchoolDbObj()->createCommand($sql)->queryRow();
  1341. if($sptr_data){
  1342. if(strpos($sptr_data['answer_url'],'http') !== false){
  1343. $answer_url = $sptr_data['answer_url'];
  1344. }else{
  1345. $answer_url = $static_url_data.$sptr_data['answer_url'];
  1346. }
  1347. $excellent_solution[(string)$v['topic_id']]['answer_url'] = $answer_url;
  1348. }
  1349. }
  1350. }
  1351. //解答题没有全部标记的情况
  1352. $sql = "select topic_id,student_id,scoring,type,answer_url from student_paper_topic_rs where paper_id = '{$paperId}' and type in (".join(",",$typeArr).") order by type asc,topic_id asc,scoring desc";
  1353. // if(empty($codeNow)){
  1354. // $sql = "select topic_id,student_id,scoring,type,answer_url from student_paper_topic_rs where paper_id = '{$paperId}' and type in (7,17,27) order by type asc,topic_id asc,scoring desc";
  1355. // }else{
  1356. // $sql = "select topic_id,student_id,scoring,type,answer_url from student_paper_topic_rs_".$codeNow." where paper_id = '{$paperId}' and type in (7,17,27) order by type asc,topic_id asc,scoring desc";
  1357. // }
  1358. $excellent_data = $this->getSchoolDbObj()->createCommand($sql)->queryAll();
  1359. if($excellent_data){
  1360. foreach($excellent_data as $k=>$v){
  1361. if(!isset($excellent_solution[(string)$v['topic_id']])){
  1362. if($v['answer_url'] && $v['scoring']>$fine_topic_score[$v['topic_id']]){
  1363. $temp_student_id = $v["student_id"];
  1364. $excellent_solution[(string)$v['topic_id']]['student_id'] = $v['student_id'];
  1365. if(strpos($v['answer_url'],'http') !== false){
  1366. $answer_url = $v['answer_url'];
  1367. }else{
  1368. $answer_url = $static_url_data.$v['answer_url'];
  1369. }
  1370. $excellent_solution[(string)$v['topic_id']]['answer_url'] = $answer_url;
  1371. //获取学生姓名
  1372. $sql = "select realname from student_info where student_id = '{$temp_student_id}'";
  1373. $student_data = $this->getSchoolDbObj()->createCommand($sql)->queryRow();
  1374. if($student_data){
  1375. $excellent_solution[(string)$v['topic_id']]['student_name'] = $student_data['realname'];
  1376. }
  1377. $excellent_solution[(string)$v['topic_id']]['class_name'] = $examInfo['class_name'];
  1378. }
  1379. }
  1380. }
  1381. }
  1382. }else{
  1383. //没有标的话取student_paper_topic_rs
  1384. $sql = "select topic_id,student_id,scoring,type,answer_url from student_paper_topic_rs where paper_id = '{$paperId}' and type in (".join(",",$typeArr).") order by type asc,topic_id asc,scoring desc";
  1385. // if(empty($codeNow)){
  1386. // $sql = "select topic_id,student_id,scoring,type,answer_url from student_paper_topic_rs where paper_id = '{$paperId}' and type in (7,17,27) order by type asc,topic_id asc,scoring desc";
  1387. // }else{
  1388. // $sql = "select topic_id,student_id,scoring,type,answer_url from student_paper_topic_rs_".$codeNow." where paper_id = '{$paperId}' and type in (7,17,27) order by type asc,topic_id asc,scoring desc";
  1389. // }
  1390. $excellent_data = $this->getSchoolDbObj()->createCommand($sql)->queryAll();
  1391. if($excellent_data){
  1392. foreach($excellent_data as $k=>$v){
  1393. if(!isset($excellent_solution[(string)$v['topic_id']])){
  1394. if($v['answer_url'] && $v['scoring']>$fine_topic_score[$v['topic_id']]){
  1395. $temp_student_id = $v["student_id"];
  1396. $excellent_solution[(string)$v['topic_id']]['student_id'] = $v['student_id'];
  1397. if(strpos($v['answer_url'],'http') !== false){
  1398. $answer_url = $v['answer_url'];
  1399. }else{
  1400. $answer_url = $static_url_data.$v['answer_url'];
  1401. }
  1402. $excellent_solution[(string)$v['topic_id']]['answer_url'] = $answer_url;
  1403. //获取学生姓名
  1404. $sql = "select realname from student_info where student_id = '{$temp_student_id}'";
  1405. $student_data = $this->getSchoolDbObj()->createCommand($sql)->queryRow();
  1406. if($student_data){
  1407. $excellent_solution[(string)$v['topic_id']]['student_name'] = $student_data['realname'];
  1408. }
  1409. $excellent_solution[(string)$v['topic_id']]['class_name'] = $examInfo['class_name'];
  1410. }
  1411. }
  1412. }
  1413. }
  1414. }
  1415. return $excellent_solution;
  1416. }
  1417. /**
  1418. * 获取选做题题号
  1419. * @param $info 题号
  1420. * @param $tpl_data_arr exam tpl_data数组
  1421. */
  1422. private function getChangeDoToicNoArr(&$info,$tplDataArr)
  1423. {
  1424. $topicNoArr = array();
  1425. foreach ($info as $item) {
  1426. $topicNoArr[$item['topic_id']] = $item['order'];
  1427. }
  1428. asort($topicNoArr);
  1429. $topicIdsArr = array_keys($topicNoArr);
  1430. $changeDoToicNo = array(
  1431. "list" => array(),//详情
  1432. "gather"=> array(),//汇总
  1433. );
  1434. //选做题题号
  1435. if (isset($tplDataArr['new_items']) && $tplDataArr['new_items']) {
  1436. foreach (array_values($tplDataArr['new_items']) as $key => $item) {
  1437. if (isset($topicIdsArr[$key]) && isset($item['sameAliasNo']) && $item['sameAliasNo']>0) {
  1438. $topic_id = $topicIdsArr[$key];
  1439. $no =$item['alias'];
  1440. $changeDoToicNo["list"][$topic_id]["sameAliasNo"] = $item['sameAliasNo'];//选做题组id
  1441. $changeDoToicNo["list"][$topic_id]["smTopicLen"] = $item['smTopicLen'];//选做题组必做数量
  1442. $changeDoToicNo["list"][$topic_id]["no"] = $no;//选做题组必做数量
  1443. $changeDoToicNo["gather"][$item['sameAliasNo']][] = $topic_id;
  1444. }
  1445. }
  1446. }
  1447. asort($changeDoToicNo);
  1448. return $changeDoToicNo;
  1449. }
  1450. }