diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index 32e87f4d0deee0e6ea8627e8ce358e5858c068fc..e8a5945a531b5f0ec57e3f6c87cf52e2dbd551ea --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ Thumbs.db *.project *.idea *nbproject +.settings +.buildpath diff --git a/db/constraints/base.sql b/db/constraints/base.sql index 1b7377fbcc4b2dda617ae4f4a2de30aaa8bd98e8..a1aa6706a64e53302d618cb4ba6aa3b79972f320 100644 --- a/db/constraints/base.sql +++ b/db/constraints/base.sql @@ -136,3 +136,9 @@ ALTER TABLE `exam_period_options` ADD CONSTRAINT `exam_period_options_ibfk_2` FOREIGN KEY (`StudentID`) REFERENCES `students` (`ID`), ADD CONSTRAINT `exam_period_options_ibfk_1` FOREIGN KEY (`SubmoduleID`) REFERENCES `submodules` (`ID`); +-- +-- Ограничения внешнего ключа таблицы `compound_disciplines` +-- +ALTER TABLE `compound_disciplines` + ADD CONSTRAINT `compound_disciplines_ibfk_1` FOREIGN KEY (`SpecializationID`) REFERENCES `specializations` (`ID`), + ADD CONSTRAINT `compound_disciplines_ibfk_2` FOREIGN KEY (`GradeID`) REFERENCES `grades` (`ID`); diff --git a/db/fixes/01_09_15.sql b/db/fixes/01_09_15.sql new file mode 100644 index 0000000000000000000000000000000000000000..a5cca162b85153e9618975e3d411e3abfba55d90 --- /dev/null +++ b/db/fixes/01_09_15.sql @@ -0,0 +1,27 @@ +DELIMITER // + +DROP TABLE IF EXISTS `compound_disciplines`// + +CREATE TABLE IF NOT EXISTS `compound_disciplines` ( + `ID` int(11) NOT NULL AUTO_INCREMENT, + `Name` varchar(200) CHARACTER SET utf8 NULL DEFAULT 'РљСѓСЂСЃ РїРѕ выбору', + `GradeID` int(11) NOT NULL, + `SpecializationID` int(11) NOT NULL, + PRIMARY KEY (`ID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 // + + +ALTER TABLE `disciplines` + ADD `CompoundDiscID` INT(11) DEFAULT NULL, + ADD KEY `CompoundDiscID` (`CompoundDiscID`)// + +ALTER TABLE `disciplines` + ADD CONSTRAINT `disciplines_ibfk_6` FOREIGN KEY (`CompoundDiscID`) REFERENCES `compound_disciplines` (`ID`) // + +ALTER TABLE `compound_disciplines` + ADD CONSTRAINT `compound_disciplines_ibfk_1` FOREIGN KEY (`SpecializationID`) REFERENCES `specializations` (`ID`), + ADD CONSTRAINT `compound_disciplines_ibfk_2` FOREIGN KEY (`GradeID`) REFERENCES `grades` (`ID`); + +DELIMITER ; + + diff --git a/db/stored/procedures.sql b/db/stored/procedures.sql index 6d83516fd4fe5a472cc68327af36c074bb7bfa7d..d2e06552f69f05b87adc3229a3209899c44d8bcc 100644 --- a/db/stored/procedures.sql +++ b/db/stored/procedures.sql @@ -776,6 +776,7 @@ BEGIN view_disciplines.IsLocked, view_disciplines.Milestone, view_disciplines.Subtype, + view_disciplines.CompoundDiscID, vIsBonus AS 'IsBonus', semesters.Num AS 'semesterNum', # TODO: Camelize semesters.Year AS 'semesterYear' @@ -806,7 +807,16 @@ BEGIN ORDER BY view_disciplines.SubjectName ASC; END // - +DROP PROCEDURE IF EXISTS GetCompoundDisciplinesForGrade// +CREATE PROCEDURE `GetCompoundDisciplinesForGrade` ( + IN `pGradeID` INT +) NO SQL +BEGIN + SELECT compound_disciplines.ID, + compound_disciplines.Name + FROM `compound_disciplines` + WHERE compound_disciplines.GradeID = pGradeID; +END // # processed format of output (after desequentialization) # { discipline1 {group1, group2, ...}, discipline2 {groupN, ...}, ... } @@ -957,6 +967,28 @@ BEGIN FROM tDisc INNER JOIN `view_disciplines` ON tDisc.DisciplineID = view_disciplines.DisciplineID WHERE view_disciplines.SemesterID = pSemesterID; +# TODO: добавить этот РєРѕРґ, С‚.Рє. РѕРЅ связан СЃ CompoundDisciplines +# view_disciplines.ExamType AS 'Type', +# view_disciplines.CompoundDiscID, +# view_disciplines.CompoundDiscName +# FROM `disciplines_groups` +# INNER JOIN `view_disciplines` ON view_disciplines.DisciplineID = disciplines_groups.DisciplineID AND +# view_disciplines.SemesterID = pSemesterID +# WHERE disciplines_groups.GroupID = pGroupID +# ) UNION DISTINCT +# (SELECT view_disciplines.DisciplineID AS 'ID', +# view_disciplines.SubjectName, +# view_disciplines.Subtype, +# view_disciplines.ExamType AS 'Type' +# FROM `disciplines_students` +# INNER JOIN `students` ON disciplines_students.StudentID = students.ID +# INNER JOIN `view_disciplines` ON view_disciplines.DisciplineID = disciplines_students.DisciplineID AND +# view_disciplines.SemesterID = pSemesterID +# INNER JOIN `students_groups` ON students_groups.StudentID = students.ID AND +# students_groups.SemesterID = pSemesterID +# WHERE students_groups.GroupID = pGroupID +# ); + END // @@ -965,6 +997,19 @@ END // # Label: rating # ------------------------------------------------------------------------------------------- +# TODO: проверить зачем это нужно +DROP PROCEDURE IF EXISTS GetDisciplineRateInfo// +CREATE PROCEDURE `GetDisciplineRateInfo` ( + IN `pDisciplineID` INT +) NO SQL +BEGIN + SELECT view_disciplines_results.DisciplineRateMax AS 'Max', + view_disciplines_results.DisciplineRateCur AS 'Current' + FROM `view_disciplines_results` + WHERE view_disciplines_results.DisciplineID = pDisciplineID + LIMIT 1; +END// + # TODO: merge with GetRatesForGroupByStage DROP PROCEDURE IF EXISTS GetRatesForGroup// CREATE PROCEDURE `GetRatesForGroup` ( @@ -1488,5 +1533,73 @@ BEGIN LIMIT 1; END // +# something useful! may be is replaced yet! +DROP PROCEDURE IF EXISTS GetRatesForGroupByStage2// +CREATE PROCEDURE `GetRatesForGroupByStage2` ( + IN `pDisciplineID` INT, + IN `pGroupID` INT, + IN `pMilestone` INT +) NO SQL +BEGIN + DECLARE vSemesterID, vGroupID INT DEFAULT -1; + SET vSemesterID = GetDisciplineProperty(pDisciplineID, 'semester'); + DROP TABLE IF EXISTS tStudents; + CREATE TEMPORARY TABLE tStudents ( + `StudentID` INT NOT NULL + ); + + # check that group attached to discipline. Otherwise vGroupID = -1; + SELECT disciplines_groups.GroupID INTO vGroupID + FROM `disciplines_groups` + WHERE disciplines_groups.GroupID = pGroupID AND + disciplines_groups.DisciplineID = pDisciplineID + LIMIT 1; + + # get all students from group, that take this discipline + IF vGroupID <= 0 THEN # doesn't attached + INSERT INTO tStudents (`StudentID`) + SELECT disciplines_students.StudentID + FROM `disciplines_students` + WHERE disciplines_students.DisciplineID = pDisciplineID AND + disciplines_students.Type = 'attach'; + ELSE # attached group + INSERT INTO tStudents (`StudentID`) + SELECT students_groups.StudentID + FROM `students_groups` + LEFT JOIN `disciplines_students` ON disciplines_students.StudentID = students_groups.StudentID AND + disciplines_students.DisciplineID = pDisciplineID + WHERE students_groups.GroupID = vGroupID AND + students_groups.SemesterID = vSemesterID AND + NOT disciplines_students.Type <=> 'detach'; # exclude detached students + END IF; + + SELECT tRes.*, + students.LastName, + students.FirstName, + students.SecondName + FROM ( + SELECT tStudents.StudentID, + SUM(tRate.Rate*(tMap.ModuleType = 'regular')) AS 'Semester', + SUM(tRate.Rate*(tMap.ModuleType = 'bonus')) AS 'Bonus', + SUM(tRate.Rate*(tMap.ModuleType = 'extra')*(tMap.SubmoduleOrderNum < pMilestone)) AS 'Extra', + SUM(tRate.Rate*(tMap.ModuleType = 'extra')*(tMap.SubmoduleOrderNum < pMilestone - 1)) AS 'PreviousExtra', + SUM(tRate.Rate*(tMap.ModuleType = 'exam')*(tMap.SubmoduleOrderNum = pMilestone)) AS 'Exam', + MAX(tRate.Rate*(tMap.ModuleType = 'exam')*(tMap.SubmoduleOrderNum < pMilestone)) AS 'PreviousExam', + MAX(tRate.Rate*(tMap.ModuleType = 'exam')*(tMap.SubmoduleOrderNum < pMilestone - 1)) AS 'PrePreviousExam', + MAX(IF(tMap.SubmoduleOrderNum = pMilestone, exam_period_options.TYPE, NULL)) As 'Option', + MAX(IF(exam_period_options.TYPE = 'pass', 1, 0)) As 'AutoPassed' + FROM `tStudents` + LEFT JOIN `view_roadmap` AS tMap ON tMap.DisciplineID = pDisciplineID + LEFT JOIN `rating_table` AS tRate ON tRate.StudentID = tStudents.StudentID AND + tRate.SubmoduleID = tMap.SubmoduleID + LEFT JOIN `exam_period_options` ON exam_period_options.submoduleID = tMap.SubmoduleID AND + exam_period_options.StudentID = tStudents.StudentID + GROUP BY tStudents.StudentID + ) tRes + INNER JOIN `students` ON students.ID = tRes.StudentID + ORDER BY students.LastName ASC, + students.FirstName ASC, + students.SecondName ASC; +END // DELIMITER ; diff --git a/db/stored/views.sql b/db/stored/views.sql index e1fe5181d2f88b6d8895a14f5523dcbbc6fa5369..48646e0130efef64ddfbdb18ea3f96fe3878fe30 100644 --- a/db/stored/views.sql +++ b/db/stored/views.sql @@ -13,8 +13,6 @@ DROP VIEW IF EXISTS `view_rating_result`; - - CREATE OR REPLACE VIEW `view_groups` AS SELECT study_groups.ID AS 'GroupID', study_groups.GroupNum AS 'GroupNum', @@ -78,6 +76,7 @@ CREATE OR REPLACE VIEW `view_disciplines` AS disciplines.IsLocked, disciplines.Milestone, disciplines.Subtype, + disciplines.CompoundDiscID, grades.ID AS 'GradeID', grades.Num AS 'GradeNum', grades.Degree, @@ -86,11 +85,14 @@ CREATE OR REPLACE VIEW `view_disciplines` AS subjects.Abbr AS 'SubjectAbbr', faculties.ID AS 'FacultyID', faculties.Name AS 'FacultyName', - faculties.Abbr AS 'FacultyAbbr' + faculties.Abbr AS 'FacultyAbbr', + compound_disciplines.Name AS 'CompoundDiscName' FROM `disciplines` INNER JOIN `subjects` ON subjects.ID = disciplines.SubjectID INNER JOIN `faculties` ON faculties.ID = disciplines.FacultyID - INNER JOIN `grades` ON grades.ID = disciplines.GradeID; + INNER JOIN `grades` ON grades.ID = disciplines.GradeID + LEFT JOIN `compound_disciplines` ON compound_disciplines.ID = disciplines.CompoundDiscID; + @@ -120,4 +122,3 @@ CREATE OR REPLACE VIEW `view_disciplines_results` AS WHERE modules.Type = 'regular' OR (modules.Type = 'exam' AND submodules.OrderNum = 1) GROUP BY disciplines.ID; - diff --git a/db/structure/base.sql b/db/structure/base.sql index c76978de0a4bcc1adcaaa9ea5c4f82d14c949d1a..7f8a30a157fe393305f7cc66e27e8a68ced54863 100644 --- a/db/structure/base.sql +++ b/db/structure/base.sql @@ -64,10 +64,28 @@ CREATE TABLE IF NOT EXISTS `departments` ( -- -------------------------------------------------------- +-- +-- Структура таблицы `compound_disciplines` +-- + +-- -------------------------------------------------------- +CREATE TABLE IF NOT EXISTS `compound_disciplines` ( + `ID` int(11) NOT NULL AUTO_INCREMENT, + `Name` varchar(200) CHARACTER SET utf8 NULL DEFAULT 'РљСѓСЂСЃ РїРѕ выбору', + `GradeID` int(11) NOT NULL, + `SpecializationID` int(11) NOT NULL, + PRIMARY KEY (`ID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + -- -- Структура таблицы `disciplines` -- +-- -------------------------------------------------------- + + CREATE TABLE IF NOT EXISTS `disciplines` ( `ID` int(11) NOT NULL AUTO_INCREMENT, `GradeID` int(11) NOT NULL, @@ -444,4 +462,3 @@ CREATE TABLE IF NOT EXISTS `exam_period_options` ( KEY `StudentID_2` (`StudentID`), KEY `StudentID_3` (`StudentID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; - diff --git a/deploy/phpConfig/database.php b/deploy/phpConfig/database.php index 73f0a6bb167d1186e641a5ece060a82466e3d18b..97c4fbf5b398039dd3554cca51be20a3d5ac4d88 100644 --- a/deploy/phpConfig/database.php +++ b/deploy/phpConfig/database.php @@ -15,7 +15,7 @@ return array */ 'dsn' => 'mysql:host=127.0.0.1;dbname=mmcs_rating', 'username' => 'mmcs_rating', - 'password' => 'Pefnesdy', +- 'password' => 'Pefnesdy', 'persistent' => FALSE, 'options' => array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8') ), diff --git a/media/js/dean/bill.js b/media/js/dean/bill.js new file mode 100644 index 0000000000000000000000000000000000000000..b67cddd90bc50d2ae19590e9d4737428648a950f --- /dev/null +++ b/media/js/dean/bill.js @@ -0,0 +1,45 @@ +$(function () { + var jSemesterSelect = $('#semesterSelect'); + var jGradeSelect = $('#gradeSelect'); + var jGroupSelect = $('#groupSelect'); + var jSpinner = $('.loadingSpinner'); + var jContent = $('.billContent'); + + jSemesterSelect.change(function () { + var sem_id = jSemesterSelect.find('option:selected').val(); + if (sem_id != 0) { + jGradeSelect.prop('disabled', false); + } else { + jGradeSelect.prop('disabled', true); + jGroupSelect.prop('disabled', true); + } + }); + + jGradeSelect.change(function () { + var gr_id = jGradeSelect.find('option:selected').val(); + if (gr_id) { + jGroupSelect.prop('disabled', false); + $.post(URLdir + 'handler/Transfer/getGroups', + {'gradeID': jGradeSelect.find('option:selected').val()}, + function (data) { + jGroupSelect.html(data); + }); + } else { + jGroupSelect.prop('disabled', true); + } + }); + + jGroupSelect.change(function () { + var gr_id = jGroupSelect.find('option:selected').val(); + if (gr_id) { + jContent.css('display', 'none'); + jSpinner.css('display', 'block'); + $.post(URLdir + 'office/bill/group/' + gr_id, + function (data) { + jSpinner.css('display', 'none'); + jContent.html(data); + jContent.css('display', 'block'); + }); + } + }); +}); \ No newline at end of file diff --git a/media/js/discipline/createDiscipline.js b/media/js/discipline/createDiscipline.js index bbc91a58678f941c8e0fe5d0549710e26af1d6ab..5b5040f6429ed4c9ab1babb9346ad416619be24c 100644 --- a/media/js/discipline/createDiscipline.js +++ b/media/js/discipline/createDiscipline.js @@ -5,6 +5,7 @@ $(function() { var jSubjectInput = $("input.InputSubject "); var jGradeSelect = $("select.SelectGrade"); var jExamTypeRadio = $("input.ExamType"); + var jCompoundSelect = $("select.SelectCompound"); // Рзменения базовых параметров дисциплины $(".AddDiscipline").click(function() @@ -26,6 +27,8 @@ $(function() { ++errCount; } + var CompoundID = parseInt(jCompoundSelect.val()); + var examType = jExamTypeRadio.filter(":radio:checked").val(); if (examType === undefined) { jExamTypeRadio.first().parent().parent().css("background-color", "#f2b4b4"); @@ -70,8 +73,16 @@ $(function() { }); jGradeSelect.change(function() { - if (parseInt($(this).val()) > 0) + if (parseInt($(this).val()) > 0) { jGradeSelect.css("border-color", INPUT_BORDER_COLOR); + jCompoundSelect.prop("disabled", false); + $.post(g_URLdir + "handler/discipline/getCompounds", {'gradeID' : parseInt($(this).val()) }, + function(data){ + jCompoundSelect.html(data.response); + }, "json"); + }else{ + jCompoundSelect.prop("disabled", true); + } }); jExamTypeRadio.change(function() { @@ -93,5 +104,5 @@ $(function() { $("input.InputPracticeCount").keydown(function(event) { KeyDownOnlyNumber(event); }); - -}); \ No newline at end of file + +}); diff --git a/media/less/bill.less b/media/less/bill.less new file mode 100644 index 0000000000000000000000000000000000000000..07d0da57b17ac45c1f34eba723ada93e8483dda3 --- /dev/null +++ b/media/less/bill.less @@ -0,0 +1,92 @@ +@import (reference) "common.less"; + +.RatingTableModulesHead { + background: #f0f7fd; +} +table { + border-top: 1px solid #ccc; + border-right: 1px solid #ccc; + color: #363636; +} + +.selectBill +{ + display: block; + width: auto; + margin: 0 auto; +} + +select { + width: 32.5% !important; + margin-right: 1.2%; + &:last-child { margin-right: 0; } +} + +.loadingSpinner { + width: 100%; + display: none; + height: 500px; + background: url(@IconSpinner); + background-repeat: no-repeat; + background-position: center; +} + +.title { + padding: 5px; + text-align: center; + table-layout: fixed; /* Фиксированная ширина ячеек */ + width: 100%; + overflow: hidden; + text-overflow: ellipsis; +} +.equal-width-cols { + width: 100%; + table-layout: fixed; +} +.equal-width-cols td { + width: 100%; +} +td { + border-left: 1px solid #ccc; + border-bottom: 1px solid #ccc; + + vertical-align: middle; +} +.student_td { + padding: 0 5px; + text-align: left; + width: 200px !important; + table-layout: fixed; /* Фиксированная ширина ячеек */ + font-size: 13px; + color: #417b9d; + overflow: hidden; + text-overflow: ellipsis; + height: 35px; +} +.debt_rate +{ + text-align: center; + color: #ff0c03; + font-weight: bold; + font-size: 14px; +} +.success_rate +{ + text-align: center; + color: #00c509; + font-weight: bold; + font-size: 14px; +} +.absent_rate +{ + text-align: center; + color: #000000; + font-size: 14px; +} +.repass_rate +{ + text-align: center; + color: #cc3ac5; + font-weight: bold; + font-size: 14px; +} diff --git a/media/less/common.less b/media/less/common.less index f06d90d34e6af8cfe7a3260d8aa0bd0bf2926312..73d09c95b28971a256be48a74237b88e1a16e54e 100644 --- a/media/less/common.less +++ b/media/less/common.less @@ -43,6 +43,7 @@ @IconTriangleUp: "@{ImagePath}icons/triangle_up.png"; @IconError: "@{ImagePath}/error.png"; @IconClose: "@{ImagePath}/close.png"; +@IconSpinner: "@{ImagePath}/ajax_loader.gif"; @IconArrowLeft: "@{ImagePath}/arrow_left.svg"; @IconArrowRight: "@{ImagePath}/arrow_right.svg"; @IconArrowLeftDouble: "@{ImagePath}/arrow_left_double.svg"; @@ -275,7 +276,7 @@ input[type="checkbox"] { // Main layer // --------------------------------------------------------------------------------------------------------------------- .main_layer { - max-width: 70%; + max-width: 85%; width: auto; min-width: 920px; margin: 35px auto; diff --git a/~dev_rating/application/bootstrap.php b/~dev_rating/application/bootstrap.php index 07ec63c0a6626fab6b63b1855af47a717a26cc31..3a174705c82eec3ab217ad088f15f872b697a063 100644 --- a/~dev_rating/application/bootstrap.php +++ b/~dev_rating/application/bootstrap.php @@ -176,6 +176,7 @@ Route::set('sign:restore', 'remind/<token>') 'action' => 'restore', ]); + // --------------- Ajax features ---------------- Route::set('handler', 'handler/<controller>(/<action>(/<id>))') ->defaults([ diff --git a/~dev_rating/application/classes/Controller/Handler/Discipline.php b/~dev_rating/application/classes/Controller/Handler/Discipline.php index 0941a831ce24c2c042509a5b364a308c6fd49e78..00c3b87400baa11a0e0eb97352c8f43e73930ea0 100644 --- a/~dev_rating/application/classes/Controller/Handler/Discipline.php +++ b/~dev_rating/application/classes/Controller/Handler/Discipline.php @@ -33,6 +33,17 @@ class Controller_Handler_Discipline extends Controller_Handler_Api return ['ID' => $discipline->ID]; } + public function action_getCompounds() { + $ret = '<option value="0"> -- Нет -- </option>'; + $compounds = Model_Grades::getCompoundDisciplinesForGrade($this->post['gradeID']); + foreach($compounds as $cmp){ + $cmpID = $cmp['ID']; + $cmpName = $cmp['Name']; + $ret .= "<option value = $cmpID> $cmpName </option>"; + } + return $ret; + } + # /handler/discipline/update public function action_update() { $this->user->checkAccess(User::RIGHTS_TEACHER); diff --git a/~dev_rating/application/classes/Controller/Office/Bill.php b/~dev_rating/application/classes/Controller/Office/Bill.php new file mode 100644 index 0000000000000000000000000000000000000000..d03880e52035ff78ebe63bef9b0b65cf01fceb54 --- /dev/null +++ b/~dev_rating/application/classes/Controller/Office/Bill.php @@ -0,0 +1,85 @@ +<?php defined('SYSPATH') or die('No direct script access.'); + +class Controller_Office_Bill extends Controller_Environment_Office +{ + public function before() { + parent::before(); + Cookie::set('fD', 'true'); + } + + public static function makeTable($groupID, &$disciplines) { + $students = Model_Students::ofGroup($groupID); + $table = []; + + foreach ($students as $stud) { + $table[$stud['ID']] = [ + 'Name' => $stud['LastName'] . ' ' . $stud['FirstName'] . ' ' . $stud['SecondName'], + 'grades' => [] + ]; + } + + + foreach ($disciplines as &$dis) { + $rates = Model_Rating::getRatesForStudentsGroupByStage2($dis['ID'], $groupID, 3); + foreach ($rates as $record) { + + if (!isset($table[$record['StudentID']])) continue; // skip fake + + $exam = max($record['PreviousExam'], $record['Exam'], $record['PrePreviousExam']); + $rate = $record['Semester'] + $record['Bonus'] + $record['Extra'] + $exam; + if ($rate > 100) { + $rate = '100+'; + } + $rateSet = isset($record['Semester']) || isset($record['Bonus']) + || isset($record['Extra']); + + if ($dis['CompoundDiscID']) { + //Выдать "звездочку", если кто-то умудрился приписать студента Рє РґРІСѓРј+ дисциплинам РёР· РѕРґРЅРѕРіРѕ compound + if (isset($table[$record['StudentID']]['grades'][-$dis['CompoundDiscID']])) { + $table[$record['StudentID']]['grades'][-$dis['CompoundDiscID']]['rating'] = + (string) $table[$record['StudentID']]['grades'][-$dis['CompoundDiscID']]['rating'] . '*'; + continue; + } + } + $table[$record['StudentID']]['grades'][($dis['CompoundDiscID'] ? -$dis['CompoundDiscID'] : $dis['ID'])] = [ + 'rating' => $rateSet ? $rate : '–' + ] + Model_Student::RecognizeDebtAndRepassing($dis, $record); + + } + //check: student may not be attach to discipline but exist in group + foreach ($students as $stud) { + if (!isset($table[$stud['ID']]['grades'][($dis['CompoundDiscID'] ? -$dis['CompoundDiscID'] : $dis['ID'])])) { + $table[$stud['ID']]['grades'][$dis['CompoundDiscID'] ? -$dis['CompoundDiscID'] : $dis['ID']] = [ + 'rating' => '–', + 'debt' => false, + 'repass' => false + ]; + } + } + } + return $table; + } + + public static function formHead(&$disciplines) { + $res = []; + foreach ($disciplines as $dis) { + if ($dis['CompoundDiscID']) { + if (!isset($res[-$dis['CompoundDiscID']])) + $res[-$dis['CompoundDiscID']] = $dis; + } else { + $res[$dis['ID']] = $dis; + } + } + return $res; + } + + public function action_group() { + $id = $this->request->param('id'); + $disciplines = Model_Group::with($id)->getDisciplines(); + $this->twig->set_filename(static::OFFICE . 'bill') + ->set([ + 'Disciplines' => self::formHead($disciplines), + 'Table' => self::makeTable($id, $disciplines) + ]); + } +} diff --git a/~dev_rating/application/classes/Controller/Office/Groups.php b/~dev_rating/application/classes/Controller/Office/Groups.php index 1c17100d1a3023d6619ac726e28b671a61615b28..79c4df368ba3c38c1f547596417d9d6727dc2227 100644 --- a/~dev_rating/application/classes/Controller/Office/Groups.php +++ b/~dev_rating/application/classes/Controller/Office/Groups.php @@ -2,5 +2,11 @@ class Controller_Office_Groups extends Controller_Environment_Office { -// public function action_index() {} + public function action_bill() + { + $this->twig->set_filename(static::OFFICE . '/groups/bill') + ->set([ + 'Grades' => Model_Grades::loadAll() + ]); + } } diff --git a/~dev_rating/application/classes/Model/Discipline.php b/~dev_rating/application/classes/Model/Discipline.php index e990e09edbe23eaf0296967902061c00fdb0c3fb..38e2a39115f0a4dfed418d60a42ddd88b9ecefda 100644 --- a/~dev_rating/application/classes/Model/Discipline.php +++ b/~dev_rating/application/classes/Model/Discipline.php @@ -21,6 +21,8 @@ * @property $IsLocked bool * @property $IsBonus bool * @property $Milestone int + * @property $CompoundDiscID int + * @property $CompoundDiscName string */ class Model_Discipline extends Model_Container { @@ -157,6 +159,14 @@ class Model_Discipline extends Model_Container ])->execute()->get('Num'); } + // Возращает текущие максимально возможные максимумы + public function getDisciplineRateInfo() { + $sql = "CALL `GetDisciplineRateInfo`(:id)"; + return DB::query(Database::SELECT, $sql) + ->param(':id', $this->ID)->execute()->as_array()[0]; + } + + /** * Time machine for discipline. * @param $stage int number from 0 to 3 @@ -174,4 +184,5 @@ class Model_Discipline extends Model_Container ':milestone' => $stage, ])->execute(); } + } diff --git a/~dev_rating/application/classes/Model/Grades.php b/~dev_rating/application/classes/Model/Grades.php index c5b7c8bf8981e617603df79ac6c3f4887bdb5147..717846a10605a84034740e2ff192c66b663d9e2f 100644 --- a/~dev_rating/application/classes/Model/Grades.php +++ b/~dev_rating/application/classes/Model/Grades.php @@ -11,4 +11,9 @@ class Model_Grades extends Model public static function loadAll() { return DB::query(Database::SELECT, 'CALL `GetGrades`()')->execute(); } + + public static function getCompoundDisciplinesForGrade($gradeID){ + return DB::query(Database::SELECT, 'CALL `GetCompoundDisciplinesForGrade`(:gradeID)') + ->param(':gradeID', $gradeID)->execute()->as_array(); + } } diff --git a/~dev_rating/application/classes/Model/Rating.php b/~dev_rating/application/classes/Model/Rating.php index 693c49950e06caef87d3eb6a91ea17979a4fbff6..c6c8a36fc7666cede69798b59ab023a3b335126c 100644 --- a/~dev_rating/application/classes/Model/Rating.php +++ b/~dev_rating/application/classes/Model/Rating.php @@ -97,6 +97,16 @@ class Model_Rating extends Model ])->execute(); } + public static function getRatesForStudentsGroupByStage2($discipline, $group, $stage) { + $sql = "CALL `GetRatesForGroupByStage2`(:discipline, :group, :stage)"; + return DB::query(Database::SELECT, $sql) + ->parameters([ + ':discipline' => $discipline, + ':group' => $group, + ':stage' => $stage + ])->execute(); + } + public static function getFinalFormInfo($discipline, $group) { $sql = "CALL `getFinalFormInfo`(:discipline, :group)"; return DB::query(Database::SELECT, $sql) diff --git a/~dev_rating/application/classes/Model/Student.php b/~dev_rating/application/classes/Model/Student.php index 1d418e10c877e4c7e9d8261677e94dd3c309c56e..e9a145822af3cacf500b7813988195a28d924c9f 100644 --- a/~dev_rating/application/classes/Model/Student.php +++ b/~dev_rating/application/classes/Model/Student.php @@ -134,4 +134,29 @@ class Model_Student extends Model_Container return $this; } + + public static function RecognizeDebtAndRepassing(Model_Discipline $discipline, $rates) { + $res = [ + 'debt' => false, + 'repass' => false + ]; + $disLimits = $discipline->getDisciplineRateInfo(); + $semester = $rates['Semester'] + $rates['PreviousExtra']; + $exam = max($rates['PrePreviousExam'], $rates['PreviousExam'], $rates['Exam']); + + $semesterRatingSetted = isset($rates['Semester']) || isset($rates['PreviousExtra']); + $examRatingSetted = isset($rates['PrePreviousExam']) || isset($rates['PreviousExam']) || isset($rates['Exam']); + + if ($examRatingSetted || $semesterRatingSetted){ + $res['debt'] = ($semester + $exam) < 0.6 * $disLimits['Current']; + } + + if ($discipline['Type'] == 'exam'){ + if ($examRatingSetted){ + $res['debt'] = $res['debt'] || $exam < 22; + $res['repass'] = (int)($rates['PrePreviousExam']) < 22 && !$res['debt']; + } + } + return $res; + } } diff --git a/~dev_rating/application/routes/dean_office.php b/~dev_rating/application/routes/dean_office.php index cf0edcf580dbd434bdd2a636566e49da65fa2da6..500925e339a04133eea828cd827f9efa10b0121c 100644 --- a/~dev_rating/application/routes/dean_office.php +++ b/~dev_rating/application/routes/dean_office.php @@ -1,15 +1,15 @@ <?php -Route::set('office:students:profile', 'office/<controller>/<id>(/(<action>))', ['id' => '\d+']) +Route::set('office:common', 'office(/(<controller>(/(<action>(/(<id>))))))', ['id' => '\d+']) ->defaults([ 'directory' => 'Office', - 'controller' => 'Students', - 'action' => 'profile', + 'controller' => 'Index', + 'action' => 'index', ]); -Route::set('office:common', 'office(/(<controller>(/(<action>))))') +Route::set('office:students:profile', 'office/<controller>/<id>(/(<action>))', ['id' => '\d+']) ->defaults([ 'directory' => 'Office', - 'controller' => 'Index', - 'action' => 'index', - ]); + 'controller' => 'Students', + 'action' => 'profile', + ]); \ No newline at end of file diff --git a/~dev_rating/application/views/office/bill.twig b/~dev_rating/application/views/office/bill.twig new file mode 100644 index 0000000000000000000000000000000000000000..ae2454d8d9b2f0bda556af827e3993a2a8c10fc9 --- /dev/null +++ b/~dev_rating/application/views/office/bill.twig @@ -0,0 +1,33 @@ +<table class="equal-width-cols"> + <tbody> + <tr class="RatingTableModulesHead"> + <td class="student_td title"> </td> + {% for dis in Disciplines %} + <td class="title"> + {% if dis.CompoundDiscID %} + {{ HTML.anchor('/compound_disciplines/' ~ dis.CompoundDiscID, + dis.CompoundDiscName, {'title': dis.CompoundDiscName })|raw }} + {% else %} + {{ HTML.anchor('/rate/' ~ dis.ID, dis.SubjectName, {'title': dis.SubjectName })|raw }} + {% endif %} + </td> + {% endfor %} + </tr> + {% for stud in Table %} + <tr> + <td class="student_td">{{ stud.Name }} </td> + {% for grade in stud.grades %} + {% if grade.debt %} + <td class="debt_rate"> {{ grade.rating }}</td> + {% elseif grade.rating=='–' %} + <td class="absent_rate"> {{ grade.rating }}</td> + {% elseif grade.repass %} + <td class="repass_rate"> {{ grade.rating }}</td> + {% else %} + <td class="success_rate"> {{ grade.rating }}</td> + {% endif %} + {% endfor %} + </tr> + {% endfor %} + </tbody> +</table> \ No newline at end of file diff --git a/~dev_rating/application/views/office/groups/!base.twig b/~dev_rating/application/views/office/groups/!base.twig new file mode 100644 index 0000000000000000000000000000000000000000..aeeda2b9d29165d6d8ff62a6d87be7d8f47a25c4 --- /dev/null +++ b/~dev_rating/application/views/office/groups/!base.twig @@ -0,0 +1,11 @@ +{% extends "office/base" %} + + +{% block office_tabs %} + <div class="tabsWrapper noTopMargin"> + <div class="tabs"> + <div class="tab">{{ HTML.anchor('office/groups/show', 'Просмотр')|raw }}</div> + <div class="tab">{{ HTML.anchor('office/groups/bill', 'Сводные ведомости')|raw }}</div> + </div> + </div> +{% endblock %} diff --git a/~dev_rating/application/views/office/groups/bill.twig b/~dev_rating/application/views/office/groups/bill.twig new file mode 100644 index 0000000000000000000000000000000000000000..08c0fea9cd5d1f8c9fd0acab29bf901f5dd2bd15 --- /dev/null +++ b/~dev_rating/application/views/office/groups/bill.twig @@ -0,0 +1,37 @@ +{% extends "office/groups/!base" %} + +{% block title %}Сводная ведомость{% endblock %} + +{% block office_media %} + {{ HTML.style('static/css/bill.css')|raw }} + {{ HTML.script('static/js/dean/bill.js')|raw }} +{% endblock %} + +{% block office_content %} + <h2>Сводная ведомость РїРѕ РіСЂСѓРїРїРµ</h2> + <div class="selectBill Margin10 Top Bottom"> + <select class="defaultForm" id="semesterSelect"> + {% for i in SemesterList %} + <option value="{{ i.ID }}"> + {{ i.Num }} семестр {{ i.Year }}/{{ i.Year + 1 }} + </option> + {% endfor %} + </select> + + <select class="defaultForm" id="gradeSelect"> + <option value="-1">-- Выберите РєСѓСЂСЃ --</option> + {% for Grade in Grades %} + <option value="{{ Grade.ID }}"> + {{ Grade.Num }} РєСѓСЂСЃ + </option> + {% endfor %} + </select> + + <select class="defaultForm" id="groupSelect"> + <option value="-1">-- Выберите РіСЂСѓРїРїСѓ --</option> + </select> + </div> + + <div class="loadingSpinner"></div> + <div class="billContent"></div> +{% endblock %} diff --git a/~dev_rating/application/views/teacher/discipline/create.twig b/~dev_rating/application/views/teacher/discipline/create.twig index 54aaca43660b169cb23646f5c7788d45b2d2c4ad..a8b5ab6d39fdb580074a41647ccd1f6a6c3d2406 100644 --- a/~dev_rating/application/views/teacher/discipline/create.twig +++ b/~dev_rating/application/views/teacher/discipline/create.twig @@ -65,6 +65,17 @@ </div> </div> </div> + <div class="LayerSection"> + <div class="itemBlock"> + <div class="title">Р’ составе объединенной дисциплины:</div> + <div class="field"> + <select class="SelectCompound defaultForm" disabled> + <option value="0">-- Нет --</option> + + </select> + </div> + </div> + </div> <div class="LayerSection"> <div class="itemBlock"> <div class="title">Бонусные баллы:</div> diff --git a/~dev_rating/static/img/ajax_loader.gif b/~dev_rating/static/img/ajax_loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..68bd58c2bbe4b49dc0787331c3488e5114c138ba Binary files /dev/null and b/~dev_rating/static/img/ajax_loader.gif differ