NotenTab: Use Points

This commit is contained in:
cgfhtw
2024-12-03 09:27:38 +01:00
parent cf6cc97475
commit 446a5732d2
7 changed files with 148 additions and 52 deletions
@@ -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
]
];
@@ -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);
}
}
@@ -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);
}
+9
View File
@@ -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;
}
+3 -2
View File
@@ -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);
}
}
@@ -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 = [
@@ -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: `
<div class="stv-details-noten-zeugnis-actions">
<select v-if="['both', 'header'].includes(config.edit)" class="form-select" v-model="current" :disabled="!selected.length">
<option value="" disabled>Note setzen</option>
<option v-for="grade in grades" :key="grade.note" :value="grade.note">{{ grade.bezeichnung }}</option>
</select>
<template v-if="['both', 'header'].includes(config.edit)">
<core-form
v-if="config.usePoints"
ref="points"
>
<form-input
type="autocomplete"
name="points"
v-model="currentPoints"
:placeholder="currentLabel"
:suggestions="suggestions"
@complete="convertPoints"
@item-select="setPoints"
optionLabel="bezeichnung"
dropdown
forceSelection
:disabled="!selected.length"
>
</form-input>
</core-form>
<select v-else class="form-select" v-model="current" :disabled="!selected.length">
<option value="" disabled>Note setzen</option>
<option v-for="grade in grades" :key="grade.note" :value="grade.note">{{ grade.bezeichnung }}</option>
</select>
</template>
</div>`
};