diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index 8c06d8bfc..111087d21 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -97,6 +97,7 @@ class Config extends FHCAPI_Controller 'showOnlyWithUid' => true, 'config' => [ 'edit' => 'both', // Possible values: both|header|inline + 'usePoints' => defined('CIS_GESAMTNOTE_PUNKTE') && CIS_GESAMTNOTE_PUNKTE ] ]; diff --git a/application/models/education/Notenschluesselaufteilung_model.php b/application/models/education/Notenschluesselaufteilung_model.php index 5017a2bbe..d48e16b0b 100644 --- a/application/models/education/Notenschluesselaufteilung_model.php +++ b/application/models/education/Notenschluesselaufteilung_model.php @@ -19,7 +19,7 @@ class Notenschluesselaufteilung_model extends DB_Model * @param integer $lehrveranstaltung_id * @param string $studiensemester_kurzbz * - * @return stdClass + * @return stdClass returns success(null) if no entry is found */ public function getNote($points, $lehrveranstaltung_id, $studiensemester_kurzbz) { @@ -38,7 +38,7 @@ class Notenschluesselaufteilung_model extends DB_Model if (isError($result)) return $result; if (!hasData($result)) - return error("Es wurde kein passender eintrag gefunden"); // TODO(chris): phrase + return success(null); return success(current(getData($result))->note); } } diff --git a/application/models/education/Notenschluesselzuordnung_model.php b/application/models/education/Notenschluesselzuordnung_model.php index 972d7adb0..9eb46b290 100644 --- a/application/models/education/Notenschluesselzuordnung_model.php +++ b/application/models/education/Notenschluesselzuordnung_model.php @@ -26,7 +26,8 @@ class Notenschluesselzuordnung_model extends DB_Model $this->db->where("lehrveranstaltung_id", $lehrveranstaltung_id); if ($studiensemester_kurzbz) { - $this->db->where_in("studiensemester_kurzbz", [$studiensemester_kurzbz, null]); + $this->db->where("studiensemester_kurzbz", $studiensemester_kurzbz); + $this->db->or_where("studiensemester_kurzbz", null); } else { $this->db->where("studiensemester_kurzbz", null); } diff --git a/public/css/Tabulator5.css b/public/css/Tabulator5.css index 4ec17cca4..29d2e7f3e 100644 --- a/public/css/Tabulator5.css +++ b/public/css/Tabulator5.css @@ -54,3 +54,12 @@ z-index: 1; outline: 0; } + + +/** + * Make keyboard-focused list items look like the mouse-hovered list items + */ +.tabulator-edit-list .tabulator-edit-list-item.focused { + color: #fff; + background: #1d68cd; +} \ No newline at end of file diff --git a/public/js/api/stv/grades.js b/public/js/api/stv/grades.js index 63aa33c00..c4532863b 100644 --- a/public/js/api/stv/grades.js +++ b/public/js/api/stv/grades.js @@ -52,7 +52,8 @@ export default { } ); }, - getGradeFromPoints(points) { - return this.$fhcApi.post('api/frontend/v1/stv/grades/getGradeFromPoints', data); + getGradeFromPoints(points, lehrveranstaltung_id, manualErrorHandling) { + const config = manualErrorHandling ? {errorHandling: false} : {}; + return this.$fhcApi.post('api/frontend/v1/stv/grades/getGradeFromPoints', {points, lehrveranstaltung_id}, config); } } \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis.js b/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis.js index 284671b52..b52c1eb1b 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis.js @@ -33,48 +33,73 @@ export default { tooltip: (evt, cell) => cell.getData().note_bezeichnung }; if (['both', 'inline'].includes(this.config.edit)) { - gradeField = {...gradeField, ...{ - editor: 'list', - editorParams: { - valuesLookup: (cell, filterTerm) => listPromise, - placeholderLoading: "Loading Remote Data...", // TODO(chris): phrase - }, - cellEdited: cell => { - // get row data - const {lehrveranstaltung_id, uid: student_uid, studiensemester_kurzbz} = cell.getData(); - // get changed value - const note = cell.getValue(); - - listPromise - // get bezeichnung - .then(list => list.find(el => el.value == note)) - .then(found => found ? found.label : Promise.reject({message: 'not found'})) - // prepare data object - .then(note_bezeichnung => ({ - lehrveranstaltung_id, - student_uid, - studiensemester_kurzbz, - note, - note_bezeichnung - })) - // send to backend - .then(this.$fhcApi.factory.stv.grades.updateCertificate) - // get bezeichnung again - .then(() => listPromise) - .then(list => list.find(el => el.value == note)) - .then(found => found ? found.label : Promise.reject({message: 'not found'})) - // update other fields in row - .then(note_bezeichnung => cell.getRow().update({note_bezeichnung})) - .then(() => cell.getRow().reformat()) - // cleanup - .then(cell.clearEdited) - .catch(err => { - cell.restoreOldValue(); - cell.clearEdited(); - this.$fhcAlert.handleFormValidation(err); - }); - } - }}; + gradeField.editor = 'list'; + gradeField.cellEdited = cell => { + // get changed value + const note = cell.getValue(); + if (note === '') + return; + + // get row data + const {lehrveranstaltung_id, uid: student_uid, studiensemester_kurzbz} = cell.getData(); + + listPromise + // get bezeichnung + .then(list => list.find(el => el.value == note)) + .then(found => found ? found.label : Promise.reject({message: 'not found'})) + // prepare data object + .then(note_bezeichnung => ({ + lehrveranstaltung_id, + student_uid, + studiensemester_kurzbz, + note, + note_bezeichnung + })) + // send to backend + .then(this.$fhcApi.factory.stv.grades.updateCertificate) + // get bezeichnung again + .then(() => listPromise) + .then(list => list.find(el => el.value == note)) + .then(found => found ? found.label : Promise.reject({message: 'not found'})) + // update other fields in row + .then(note_bezeichnung => cell.getRow().update({note_bezeichnung})) + .then(() => cell.getRow().reformat()) + // cleanup + .then(cell.clearEdited) + .catch(err => { + cell.restoreOldValue(); + cell.clearEdited(); + this.$fhcAlert.handleFormValidation(err); + }); + }; + if (this.config.usePoints) { + gradeField.editorParams = { + valuesLookup: (cell, filterTerm) => { + if (filterTerm) { + return this.$fhcApi.factory + .stv.grades.getGradeFromPoints(filterTerm, cell.getData().lehrveranstaltung_id, true) + .then(result => + result.data === null + ? [] + : listPromise.then(res => res.filter(grade => grade.value === result.data)) + ) + .catch(err => []); + } + return listPromise; + }, + autocomplete: true, + filterRemote: true, + allowEmpty: true, + listOnEmpty: true + }; + gradeField.cellEditing = cell => cell.setValue(''); + gradeField.cellEditCancelled = cell => cell; + } else { + gradeField.editorParams = { + valuesLookup: (cell, filterTerm) => listPromise + }; + } + gradeField.editorParams.placeholderLoading = "Loading Remote Data..." // TODO(chris): phrase } const columns = [ diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis/Actions.js b/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis/Actions.js index 0c4c7e7bf..e82b84234 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis/Actions.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis/Actions.js @@ -1,4 +1,12 @@ +import CoreForm from '../../../../../Form/Form.js'; +import FormInput from '../../../../../Form/Input.js'; + + export default { + components: { + CoreForm, + FormInput + }, emits: [ 'setGrades' ], @@ -10,7 +18,9 @@ export default { }, data() { return { - grades: [] + grades: [], + suggestions: null, + currentPoints: '' }; }, computed: { @@ -34,6 +44,34 @@ export default { return { lehrveranstaltung_id, student_uid, studiensemester_kurzbz, note }; })); } + }, + currentLabel() { + if (this.current == '') + return 'Note setzen'; // TODO(chris): phrase + return this.grades.find(grade => grade.note === this.current)?.bezeichnung || ''; + } + }, + methods: { + convertPoints({evt, query}) { + if (!query) { + return this.suggestions = this.grades; + } + this.$refs.points.factory + .stv.grades.getGradeFromPoints(query, this.selected.find(Boolean)?.lehrveranstaltung_id) + .then(result => { + if (result.data === null) { + this.suggestions = []; + return result; + } + this.suggestions = this.grades.filter(grade => grade.note == result.data); + }) + .catch(this.$fhcAlert.handleSystemError); + }, + setPoints({evt, value: {note}}) { + if (this.selected) + this.selected.forEach(grade => grade.note = note); + this.currentPoints = ''; + this.current = note; } }, created() { @@ -47,9 +85,30 @@ export default { // TODO(chris): phrases template: `
- +
` }; \ No newline at end of file