mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-20 00:12:15 +00:00
custom sticky css; offcanvas mobility legende; mobiltiy zusatz in seperate column; added getMobilityZusatzForUids & formatZusatz similar to digital anw mobility zusaetze;
This commit is contained in:
@@ -31,7 +31,7 @@ class Benotungstool extends Auth_Controller
|
||||
|
||||
// TODO: check if related CIS config is also loaded when being routed in Cis4 by vuerouter
|
||||
// TODO: check if new benotungstool should be configurable the exact same way?
|
||||
|
||||
// TODO: move this to some config api?
|
||||
|
||||
$viewData = array(
|
||||
'uid'=>getAuthUID(),
|
||||
|
||||
@@ -59,6 +59,8 @@ class Noten extends FHCAPI_Controller
|
||||
$this->load->model('person/Person_model', 'PersonModel');
|
||||
$this->load->model('organisation/Studienplan_model', 'StudienplanModel');
|
||||
$this->load->model('crm/Student_model', 'StudentModel');
|
||||
$this->load->model('codex/Mobilitaet_model', 'MobilitaetModel');
|
||||
$this->load->model('organisation/Erhalter_model', 'ErhalterModel');
|
||||
|
||||
$this->load->helper('hlp_sancho_helper');
|
||||
|
||||
@@ -92,26 +94,24 @@ class Noten extends FHCAPI_Controller
|
||||
$grades = array();
|
||||
$student_uids = array_map($func, $studentenData);
|
||||
|
||||
if(count($student_uids) > 0) {
|
||||
$mobres = $this->MobilitaetModel->getMobilityZusatzForUids($student_uids);
|
||||
$mobData = $this->getDataOrTerminateWithError($mobres);
|
||||
|
||||
$result = $this->ErhalterModel->load();
|
||||
$erhalter = getData($result)[0];
|
||||
|
||||
$erhalter_kz = '9' . sprintf("%03s", $erhalter->erhalter_kz);
|
||||
foreach($mobData as $mob) {
|
||||
$grades[$mob->uid]['mobility_zusatz'] = $this->MobilitaetModel->formatZusatz($mob, $erhalter_kz);
|
||||
}
|
||||
}
|
||||
|
||||
foreach($student_uids as $uid) {
|
||||
$grades[$uid]['grades'] = [];
|
||||
|
||||
$res = $this->StudentModel->load([$uid]);
|
||||
if(!isError($res) && hasData($res)) $student = getData($res)[0];
|
||||
|
||||
$prestudent_id = $student->prestudent_id;
|
||||
|
||||
|
||||
// TODO: last class to get rid of but this one is complicated
|
||||
$mobility = new mobilitaet();
|
||||
$mobility->loadPrestudent($prestudent_id);
|
||||
$output = $mobility->result;
|
||||
$eintrag = '';
|
||||
foreach ($output as $k)
|
||||
{
|
||||
if(($k->mobilitaetstyp_kurzbz == 'GS') && ($k->studiensemester_kurzbz == $sem_kurzbz))
|
||||
$eintrag = ' (d.d.)';
|
||||
}
|
||||
$grades[$uid]['mobility'] = $eintrag;
|
||||
|
||||
$result = $this->LvgesamtnoteModel->getLvGesamtNoten($lv_id, $uid, $sem_kurzbz);
|
||||
|
||||
@@ -131,6 +131,7 @@ class Noten extends FHCAPI_Controller
|
||||
|
||||
// send $grades reference to moodle addon
|
||||
// TODO: DONT LET FAULTY MOODLE TOKEN BREAK THE STARTUP
|
||||
|
||||
// Events::trigger(
|
||||
// 'getExternalGrades',
|
||||
// function & () use (&$grades)
|
||||
@@ -142,6 +143,8 @@ class Noten extends FHCAPI_Controller
|
||||
// 'stsem' => $sem_kurzbz
|
||||
// ]
|
||||
// );
|
||||
|
||||
|
||||
|
||||
// calculate notenvorschläge from teilnoten
|
||||
foreach($studentenData as $student) {
|
||||
|
||||
@@ -11,4 +11,73 @@ class Mobilitaet_model extends DB_Model
|
||||
$this->dbTable = 'bis.tbl_mobilitaet';
|
||||
$this->pk = 'mobilitaet_id';
|
||||
}
|
||||
|
||||
public function getMobilityZusatzForUids($uids) {
|
||||
$qry = "SELECT distinct on(nachname, vorname, public.tbl_benutzer.person_id) uid,
|
||||
tbl_mitarbeiter.mitarbeiter_uid,
|
||||
tbl_note.lkt_ueberschreibbar, tbl_note.anmerkung,
|
||||
tbl_mobilitaet.mobilitaetstyp_kurzbz,
|
||||
(CASE WHEN bis.tbl_mobilitaet.studiensemester_kurzbz = vw_student_lehrveranstaltung.studiensemester_kurzbz THEN 1 ELSE 0 END) as doubledegree,
|
||||
public.tbl_prestudent.gsstudientyp_kurzbz as ddtype,
|
||||
(SELECT status_kurzbz FROM public.tbl_prestudentstatus
|
||||
WHERE prestudent_id=tbl_student.prestudent_id
|
||||
ORDER BY datum DESC, insertamum DESC, ext_id DESC LIMIT 1) as studienstatus
|
||||
FROM
|
||||
campus.vw_student_lehrveranstaltung
|
||||
JOIN public.tbl_benutzer USING(uid)
|
||||
JOIN public.tbl_person USING(person_id)
|
||||
LEFT JOIN public.tbl_student ON(uid=student_uid)
|
||||
LEFT JOIN public.tbl_mitarbeiter ON(uid=mitarbeiter_uid)
|
||||
LEFT JOIN public.tbl_studentlehrverband USING(student_uid,studiensemester_kurzbz)
|
||||
LEFT JOIN lehre.tbl_zeugnisnote on(vw_student_lehrveranstaltung.lehrveranstaltung_id=tbl_zeugnisnote.lehrveranstaltung_id
|
||||
AND tbl_zeugnisnote.student_uid=tbl_student.student_uid
|
||||
AND tbl_zeugnisnote.studiensemester_kurzbz=tbl_studentlehrverband.studiensemester_kurzbz)
|
||||
LEFT JOIN lehre.tbl_note USING (note)
|
||||
LEFT JOIN bis.tbl_bisio ON(uid=tbl_bisio.student_uid)
|
||||
LEFT JOIN public.tbl_studiengang ON(tbl_student.studiengang_kz=tbl_studiengang.studiengang_kz)
|
||||
LEFT JOIN bis.tbl_mobilitaet USING(prestudent_id)
|
||||
LEFT JOIN public.tbl_prestudent USING(prestudent_id)
|
||||
WHERE uid IN ?";
|
||||
|
||||
return $this->execReadOnlyQuery($qry, [$uids]);
|
||||
}
|
||||
|
||||
public function formatZusatz($entry, $erhalter_kz) {
|
||||
$zusatz = '';
|
||||
|
||||
if (isset($entry->studienstatus) && $entry->studienstatus === 'Incoming') {
|
||||
$zusatz = '(i)';
|
||||
}
|
||||
|
||||
if (isset($entry->lkt_ueberschreibbar) && $entry->lkt_ueberschreibbar === false) {
|
||||
$zusatz .= ' (' . ($entry->anmerkung ?? '') . ')';
|
||||
}
|
||||
|
||||
if (isset($entry->mitarbeiter_uid) && $entry->mitarbeiter_uid !== null) {
|
||||
$zusatz .= ' (ma)';
|
||||
}
|
||||
|
||||
if (isset($entry->stg_kz_student) && $entry->stg_kz_student == $erhalter_kz) {
|
||||
$zusatz .= ' (a.o.)';
|
||||
}
|
||||
|
||||
if (
|
||||
isset($entry->mobilitaetstyp_kurzbz) && $entry->mobilitaetstyp_kurzbz &&
|
||||
isset($entry->doubledegree) && $entry->doubledegree === 1
|
||||
) {
|
||||
$zusatz .= ' (d.d.';
|
||||
|
||||
$ddtype = $entry->ddtype ?? null;
|
||||
|
||||
if ($ddtype == 'Intern') {
|
||||
$zusatz .= 'i.)';
|
||||
} elseif ($ddtype == 'Extern') {
|
||||
$zusatz .= 'o.)';
|
||||
} else {
|
||||
$zusatz .= ')';
|
||||
}
|
||||
}
|
||||
|
||||
return $zusatz;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -898,8 +898,4 @@ class Prestudent_model extends DB_Model
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getMobilityPrestudent(){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ $includesArray = array(
|
||||
'public/css/components/FormUnderline.css',
|
||||
'public/css/Cis4/Cms.css',
|
||||
'public/css/Cis4/Studium.css',
|
||||
'public/css/Cis4/Benotungstool.css'
|
||||
),
|
||||
'customJSs' => array(
|
||||
'vendor/npm-asset/primevue/accordion/accordion.min.js',
|
||||
|
||||
@@ -36,4 +36,4 @@ $this->load->view('templates/FHC-Header', $includesArray);
|
||||
></cis-menu>
|
||||
</header>
|
||||
|
||||
<main id="cis-main" class="flex-grow-1 p-4 pt-2">
|
||||
<main id="cis-main" class="flex-grow-1 p-4 pt-2" style="min-width: 0;">
|
||||
@@ -0,0 +1,41 @@
|
||||
/* 1. Stick the Header */
|
||||
#notentable .tabulator-header .tabulator-col.sticky-col {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
z-index: 10; /* Must be higher than other headers */
|
||||
background-color: #fff; /* Opaque background is required */
|
||||
border-right: 2px solid #ddd; /* Optional: Separator line */
|
||||
}
|
||||
|
||||
/* 2. Stick the Data Cells */
|
||||
#notentable .tabulator-tableholder .tabulator-row .tabulator-cell.sticky-col {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
z-index: 10; /* Ensure it floats above other cells */
|
||||
background-color: #fff; /* Match your row background color */
|
||||
border-right: 2px solid #ddd; /* Optional: Separator line */
|
||||
}
|
||||
|
||||
/* 3. Fix for Hover Effects (Optional) */
|
||||
/* If you use hover rows, you need to ensure the sticky cell matches the hover color */
|
||||
#notentable .tabulator-row:hover .tabulator-cell.sticky-col {
|
||||
background-color: #ccc; /* Match your existing hover color */
|
||||
}
|
||||
|
||||
|
||||
/* styling for editable dropdown column of notenvorschläge in benotungstool*/
|
||||
#notentable .tabulator-tableholder .tabulator-editable {
|
||||
position: relative;
|
||||
background-color: rgba(255, 255, 157, 0.73);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#notentable .tabulator-tableholder .tabulator-editable::after {
|
||||
content: "▾";
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
color: rgba(176, 176, 106, 0.73);;
|
||||
font-size: x-large;
|
||||
bottom: 6px;
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -854,21 +854,4 @@ html {
|
||||
#cis-main .modal-footer {
|
||||
background-color: var(--fhc-secondary);
|
||||
|
||||
}
|
||||
|
||||
/* styling for editable dropdown column of notenvorschläge in benotungstool*/
|
||||
#notentable .tabulator-tableholder .tabulator-editable {
|
||||
position: relative;
|
||||
background-color: rgba(255, 255, 157, 0.73);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#notentable .tabulator-tableholder .tabulator-editable::after {
|
||||
content: "▾";
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
color: rgba(176, 176, 106, 0.73);;
|
||||
font-size: x-large;
|
||||
bottom: 6px;
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
export default {
|
||||
name: 'BootstrapOffcanvas',
|
||||
data: () => ({
|
||||
offcanvas: null
|
||||
}),
|
||||
props: {
|
||||
backdrop: {
|
||||
type: [Boolean, String],
|
||||
default: true,
|
||||
validator(value) {
|
||||
return ['static', true, false].includes(value);
|
||||
}
|
||||
},
|
||||
keyboard: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
scroll: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
placement: {
|
||||
type: String,
|
||||
default: 'start', // start | end | top | bottom
|
||||
validator(value) {
|
||||
return ['start', 'end', 'top', 'bottom'].includes(value);
|
||||
}
|
||||
},
|
||||
noCloseBtn: Boolean,
|
||||
headerClass: {
|
||||
type: [String, Array, Object],
|
||||
default: ''
|
||||
},
|
||||
bodyClass: {
|
||||
type: [String, Array, Object],
|
||||
default: 'p-4'
|
||||
},
|
||||
footerClass: {
|
||||
type: [String, Array, Object],
|
||||
default: ''
|
||||
},
|
||||
dialogClass: [String, Array, Object]
|
||||
},
|
||||
emits: [
|
||||
"hideBsOffcanvas",
|
||||
"hiddenBsOffcanvas",
|
||||
"hidePreventedBsOffcanvas",
|
||||
"showBsOffcanvas",
|
||||
"shownBsOffcanvas"
|
||||
],
|
||||
methods: {
|
||||
dispose() {
|
||||
return this.offcanvas?.dispose();
|
||||
},
|
||||
hide() {
|
||||
return this.offcanvas?.hide();
|
||||
},
|
||||
show(relatedTarget) {
|
||||
return this.offcanvas?.show(relatedTarget);
|
||||
},
|
||||
toggle() {
|
||||
return this.offcanvas?.toggle();
|
||||
},
|
||||
popup(body, options, title, footer) {
|
||||
const BsOffcanvas = this,
|
||||
slots = {};
|
||||
|
||||
if (body !== undefined)
|
||||
slots.default = () => body;
|
||||
if (title !== undefined)
|
||||
slots.title = () => title;
|
||||
if (footer !== undefined)
|
||||
slots.footer = () => footer;
|
||||
|
||||
let includedPrimevue = false;
|
||||
if (typeof primevue !== 'undefined')
|
||||
includedPrimevue = true;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const instance = Vue.createApp({
|
||||
name: 'OffcanvasTmpApp',
|
||||
setup() {
|
||||
return () =>
|
||||
Vue.h(BsOffcanvas, {
|
||||
class: 'offcanvas-wrapper',
|
||||
ref: 'offcanvas',
|
||||
...options
|
||||
}, slots);
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.offcanvas.show();
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (this.$refs.offcanvas)
|
||||
this.$refs.offcanvas.result !== false ? resolve(this.$refs.offcanvas.result) : reject();
|
||||
},
|
||||
unmounted() {
|
||||
wrapper.parentElement.removeChild(wrapper);
|
||||
}
|
||||
});
|
||||
const wrapper = document.createElement('div');
|
||||
|
||||
if (includedPrimevue) {
|
||||
instance.use(primevue.config.default, { zIndex: { overlay: 9999 } });
|
||||
}
|
||||
|
||||
import('../../plugins/Phrasen.js').then((Phrasen) => {
|
||||
instance.use(Phrasen.default);
|
||||
instance.mount(wrapper);
|
||||
document.body.appendChild(wrapper);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.$refs.offcanvas) {
|
||||
this.offcanvas = new bootstrap.Offcanvas(this.$refs.offcanvas, {
|
||||
backdrop: this.backdrop,
|
||||
keyboard: this.keyboard,
|
||||
scroll: this.scroll
|
||||
});
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div ref="offcanvas"
|
||||
class="bootstrap-offcanvas offcanvas"
|
||||
:class="['offcanvas-' + placement, dialogClass]"
|
||||
tabindex="-1"
|
||||
@[\`hide.bs.offcanvas\`]="$emit('hideBsOffcanvas')"
|
||||
@[\`hidden.bs.offcanvas\`]="$emit('hiddenBsOffcanvas')"
|
||||
@[\`hidePrevented.bs.offcanvas\`]="$emit('hidePreventedBsOffcanvas')"
|
||||
@[\`show.bs.offcanvas\`]="$emit('showBsOffcanvas')"
|
||||
@[\`shown.bs.offcanvas\`]="$emit('shownBsOffcanvas')"
|
||||
>
|
||||
<div class="offcanvas-header" :class="headerClass" v-if="$slots.title">
|
||||
<h5 class="offcanvas-title">
|
||||
<slot name="title"></slot>
|
||||
</h5>
|
||||
<button v-if="!noCloseBtn" type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<div class="offcanvas-body" :class="bodyClass">
|
||||
<slot></slot>
|
||||
</div>
|
||||
|
||||
<div v-if="$slots.footer" class="offcanvas-footer" :class="footerClass">
|
||||
<slot name="footer"></slot>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import ApiLehre from "../../../api/factory/lehre.js";
|
||||
import ApiNoten from "../../../api/factory/noten.js";
|
||||
import ApiStudiensemester from "../../../api/factory/studiensemester.js";
|
||||
import BsModal from '../../Bootstrap/Modal.js';
|
||||
import BsOffcanvas from '../../Bootstrap/Offcanvas.js';
|
||||
import VueDatePicker from '../../vueDatepicker.js.php';
|
||||
import LehreinheitenModule from '../../DropdownModes/LehreinheitenModule';
|
||||
import MobilityLegende from '../../Mobility/Legende.js';
|
||||
@@ -12,6 +13,7 @@ export const Benotungstool = {
|
||||
name: "Benotungstool",
|
||||
components: {
|
||||
BsModal,
|
||||
BsOffcanvas,
|
||||
CoreFilterCmpt,
|
||||
MobilityLegende,
|
||||
Dropdown: primevue.dropdown,
|
||||
@@ -43,8 +45,6 @@ export const Benotungstool = {
|
||||
data() {
|
||||
return {
|
||||
neuesPruefungsdatumModalVisible: false,
|
||||
offsetLeft: 0,
|
||||
headerEl: null,
|
||||
loading: false,
|
||||
selectedUids: [], // shared selection state
|
||||
selectedLehreinheit: null,
|
||||
@@ -116,6 +116,17 @@ export const Benotungstool = {
|
||||
row.reformat() // trigger reformat of arrow
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
event: "cellClick",
|
||||
handler: async (e, cell) => {
|
||||
const field = cell.getField()
|
||||
|
||||
if(field == "mobility_zusatz") {
|
||||
this.$refs.drawer.show()
|
||||
e.stopPropagation()
|
||||
}
|
||||
}
|
||||
}
|
||||
]};
|
||||
},
|
||||
@@ -258,7 +269,12 @@ export const Benotungstool = {
|
||||
this.loading = true
|
||||
this.$api.call(ApiNoten.saveNotenvorschlagBulk(this.lv_id, this.sem_kurzbz, notenbulk)).then(res => {
|
||||
if(res.meta.status === 'success') {
|
||||
this.$fhcAlert.alertSuccess(this.$p.t('benotungstool/notenImportSuccessAlert'))
|
||||
this.$fhcAlert.alertDefault(
|
||||
'success',
|
||||
'Info',
|
||||
this.$p.t('benotungstool/notenImportSuccessAlert'),
|
||||
true
|
||||
)
|
||||
const lvNoten = res.data
|
||||
|
||||
|
||||
@@ -289,7 +305,12 @@ export const Benotungstool = {
|
||||
this.$api.call(ApiNoten.saveStudentPruefungBulk(this.lv_id, this.sem_kurzbz, pruefungenbulk))
|
||||
.then((res)=> {
|
||||
if(res.meta.status === 'success') {
|
||||
this.$fhcAlert.alertSuccess(this.$p.t('benotungstool/pruefungImportSuccessAlert'))
|
||||
this.$fhcAlert.alertDefault(
|
||||
'success',
|
||||
'Info',
|
||||
this.$p.t('benotungstool/pruefungImportSuccessAlert'),
|
||||
true
|
||||
)
|
||||
this.handleAddNewPruefungenResponse(res, pruefungenbulk)
|
||||
}
|
||||
}).finally(()=>{this.loading = false})
|
||||
@@ -426,8 +447,8 @@ export const Benotungstool = {
|
||||
},
|
||||
getNotenTableOptions() {
|
||||
return {
|
||||
rowHeight: 40,
|
||||
height: 700,
|
||||
virtualDom: false,
|
||||
index: 'uid',
|
||||
layout: 'fitDataStretch',
|
||||
placeholder: this.$p.t('global/noDataAvailable'),
|
||||
@@ -442,6 +463,7 @@ export const Benotungstool = {
|
||||
|
||||
return true; // student can be selected to add pruefung
|
||||
},
|
||||
rowHeight: 40,
|
||||
rowFormatter: this.fixTabulatorSelectionFormatter,
|
||||
columns: [
|
||||
{
|
||||
@@ -488,13 +510,15 @@ export const Benotungstool = {
|
||||
handleClick: this.selectAllHandler
|
||||
},
|
||||
width: 50,
|
||||
},
|
||||
{title: Vue.computed(() => this.$p.t('benotungstool/c4mail')), field: 'email', formatter: this.mailFormatter, tooltip: false, widthGrow: 1},
|
||||
{title: Vue.computed(() => this.$p.t('benotungstool/c4antrittCount')), field: 'hoechsterAntritt', tooltip: false, widthGrow: 1},
|
||||
{title: 'UID', field: 'uid', tooltip: false, widthGrow: 1, topCalc: this.sumCalcFunc},
|
||||
cssClass: 'sticky-col'
|
||||
},
|
||||
{title: 'UID', field: 'uid', tooltip: false, widthGrow: 1, topCalc: this.sumCalcFunc, cssClass: 'sticky-col'},
|
||||
{title: Vue.computed(() => this.$p.t('benotungstool/c4mail')), field: 'email', formatter: this.mailFormatter, tooltip: false, visible: false, widthGrow: 1, variableHeight: true},
|
||||
{title: Vue.computed(() => this.$p.t('benotungstool/c4antrittCountv2')), field: 'hoechsterAntritt', tooltip: false, widthGrow: 1},
|
||||
{title: Vue.computed(() => this.$p.t('benotungstool/c4vorname')), field: 'vorname', headerFilter: true, tooltip: false, widthGrow: 1},
|
||||
{title: Vue.computed(() => this.$p.t('benotungstool/c4nachname')), field: 'nachname', headerFilter: true, widthGrow: 1},
|
||||
{title: Vue.computed(() => this.$p.t('benotungstool/c4teilnoten')), field: 'teilnote', widthGrow: 1, formatter: this.teilnotenFormatter},
|
||||
{title: Vue.computed(() => this.$p.t('benotungstool/c4nachname')), field: 'nachname', headerFilter: true, widthGrow: 1},
|
||||
{title: Vue.computed(() => this.$p.t('benotungstool/c4mobility')), field: 'mobility_zusatz', headerFilter: true, widthGrow: 1, visible: false},
|
||||
{title: Vue.computed(() => this.$p.t('benotungstool/c4teilnoten')), field: 'teilnote', widthGrow: 1, formatter: this.teilnotenFormatter, variableHeight: true},
|
||||
{title: Vue.computed(() => this.$p.t('benotungstool/c4note')), field: 'note_vorschlag',
|
||||
editor: 'list',
|
||||
editorParams: (cell) => {
|
||||
@@ -531,8 +555,9 @@ export const Benotungstool = {
|
||||
if(p || !match?.lkt_ueberschreibbar) style = 'color: gray;font-style: italic; background-color: #f0f0f0;pointer-events: none;opacity: 0.6;user-select: none;cursor: not-allowed;'
|
||||
return '<div style="'+style+'">' + val + '</div>'
|
||||
},
|
||||
widthGrow: 1},
|
||||
{title: '', width: 50, hozAlign: 'center', formatter: this.arrowFormatter, cellClick: this.saveNote},
|
||||
widthGrow: 1
|
||||
},
|
||||
{title: '', width: 50, hozAlign: 'center', formatter: this.arrowFormatter, cellClick: this.saveNote, variableHeight: true},
|
||||
{title: Vue.computed(() => this.$p.t('benotungstool/c4lvnote')), field: 'lv_note',
|
||||
formatter: this.notenFormatter,
|
||||
headerFilter: 'list',
|
||||
@@ -540,8 +565,9 @@ export const Benotungstool = {
|
||||
return { values: ["\u00A0",this.$p.t('benotungstool/c4noteEmpty') ,this.$p.t('benotungstool/c4positiv'), this.$p.t('benotungstool/c4negativ') ,...this.notenOptions.map(opt => opt.bezeichnung)] }
|
||||
},
|
||||
headerFilterFunc: this.notenFilterFunc,
|
||||
widthGrow: 1},
|
||||
{title: Vue.computed(() => this.$p.t('benotungstool/c4freigabe')), field: 'freigegeben', widthGrow: 1, formatter: this.freigabeFormatter},
|
||||
widthGrow: 1
|
||||
},
|
||||
{title: Vue.computed(() => this.$p.t('benotungstool/c4freigabe')), field: 'freigegeben', widthGrow: 1, formatter: this.freigabeFormatter, variableHeight: true},
|
||||
{title: Vue.computed(() => this.$p.t('benotungstool/c4zeugnisnote')),
|
||||
field: 'note',
|
||||
formatter: this.notenFormatter,
|
||||
@@ -552,13 +578,15 @@ export const Benotungstool = {
|
||||
return { values: ["\u00A0", this.$p.t('benotungstool/c4noteEmpty'),this.$p.t('benotungstool/c4positiv'), this.$p.t('benotungstool/c4negativ') ,...this.notenOptions.map(opt => opt.bezeichnung)] }
|
||||
},
|
||||
headerFilterFunc: this.notenFilterFunc,
|
||||
widthGrow: 1},
|
||||
widthGrow: 1
|
||||
},
|
||||
{title: Vue.computed(() => this.$p.t('benotungstool/c4kommPruef')),
|
||||
field: 'kommPruef', widthGrow: 1,
|
||||
formatter: this.pruefungFormatter,
|
||||
topCalc: this.terminCalcFunc,
|
||||
topCalcFormatter: this.terminCalcFormatter,
|
||||
hozAlign:"center", minWidth: 150}
|
||||
hozAlign:"center", minWidth: 150, visible: false
|
||||
}
|
||||
],
|
||||
persistence: false,
|
||||
}
|
||||
@@ -701,14 +729,16 @@ export const Benotungstool = {
|
||||
freigabeFormatter(cell) {
|
||||
const value = cell.getValue()
|
||||
|
||||
let style = 'display: flex; justify-content: center; align-items: center; height: 100%;'
|
||||
|
||||
if(value === 'ok') {
|
||||
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
|
||||
return '<div style="'+style+'">' +
|
||||
'<i class="fa fa-circle-check" style="color:green"></i></div>'
|
||||
} else if (value === 'offen') {
|
||||
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
|
||||
return '<div style="'+style+'">' +
|
||||
'<i class="fa-regular fa-circle"></i></div>'
|
||||
} else if (value === 'changed') {
|
||||
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
|
||||
return '<div style="'+style+'">' +
|
||||
'<i class="fa fa-circle-check"></i></div>'
|
||||
}
|
||||
|
||||
@@ -741,11 +771,14 @@ export const Benotungstool = {
|
||||
},
|
||||
teilnotenFormatter(cell) {
|
||||
const val = cell.getValue()
|
||||
return '<div style="white-space: pre-line;">'+val+'</div>'
|
||||
|
||||
let style = 'white-space: pre-line;'
|
||||
|
||||
return '<div style="">'+val+'</div>'
|
||||
},
|
||||
pruefungFormatter(cell) {
|
||||
const data = cell.getData()
|
||||
|
||||
|
||||
const noteDef = data.note ? this.notenOptions.find(n => n.note == data.note) : null
|
||||
if(!data.note || !noteDef?.lkt_ueberschreibbar) {
|
||||
return ''
|
||||
@@ -901,18 +934,23 @@ export const Benotungstool = {
|
||||
const row = cell.getRow()
|
||||
const data = row.getData()
|
||||
|
||||
let style = 'display: flex; justify-content: center; align-items: center; height: 100%;'
|
||||
|
||||
if(!data.note_vorschlag || (data.note_vorschlag == data.lv_note)) { // uncolored arrow
|
||||
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
|
||||
return '<div style="'+style+'">' +
|
||||
'<i class="fa fa-arrow-right"></i></div>'
|
||||
}
|
||||
|
||||
// can save a notenvorschlag -> colored
|
||||
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
|
||||
return '<div style="'+style+'">' +
|
||||
'<i class="fa fa-arrow-right fa-2xl" style="color:#00649C"></i></div>'
|
||||
},
|
||||
mailFormatter(cell) {
|
||||
const val = cell.getValue()
|
||||
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
|
||||
|
||||
let style = 'display: flex; justify-content: center; align-items: center; height: 100%;'
|
||||
|
||||
return '<div style="'+style+'">' +
|
||||
'<a href='+val+'><i class="fa fa-envelope" style="color:#00649C"></i></a></div>'
|
||||
},
|
||||
buildMailToLink(student){
|
||||
@@ -999,7 +1037,7 @@ export const Benotungstool = {
|
||||
|
||||
const grades = this.teilnoten[s.uid].grades
|
||||
s.teilnote = ''
|
||||
|
||||
s.mobility_zusatz = this.teilnoten[s.uid].mobility_zusatz
|
||||
grades.forEach(g => {
|
||||
const notenOption = this.notenOptions.find(n=>n.note == g.grade)
|
||||
if(notenOption.positiv) s.teilnote += ('<span>'+g.text +'</span>'+ '<br/>')
|
||||
@@ -1121,29 +1159,8 @@ export const Benotungstool = {
|
||||
this.tableBuiltPromise = new Promise(this.tableResolve)
|
||||
await this.tableBuiltPromise
|
||||
|
||||
this.headerEl = document.getElementById('nav-main')
|
||||
if(this.headerEl) {
|
||||
this.headerEl.addEventListener("shown.bs.collapse", this.handleSidebar);
|
||||
this.headerEl.addEventListener("hidden.bs.collapse", this.handleSidebar);
|
||||
this.handleSidebar()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
this.loadNoten(this.lv_id, this.sem_kurzbz)
|
||||
// this.calcMaxTableHeight()
|
||||
|
||||
},
|
||||
handleSidebar() {
|
||||
// this.$refs.notenTable.tabulator.blockRedraw(); // stop automatic resizes
|
||||
|
||||
this.offsetLeft = this.headerEl.getBoundingClientRect().width;
|
||||
|
||||
// setTimeout(() => {
|
||||
// this.$refs.notenTable.tabulator.restoreRedraw(); // re-enable
|
||||
// this.$refs.notenTable.tabulator.redraw(true); // manual recalculation
|
||||
// }, 400); // after animation finishes
|
||||
this.calcMaxTableHeight()
|
||||
|
||||
},
|
||||
lvChanged(e) {
|
||||
@@ -1233,8 +1250,12 @@ export const Benotungstool = {
|
||||
typ
|
||||
)).then(res => {
|
||||
if(res.meta.status === 'success') { //'Prüfung für Student ' + this.pruefungStudent.uid + ' bearbeitet oder angelegt'
|
||||
this.$fhcAlert.alertSuccess(this.$p.t('benotungstool/pruefungSaveForUid', [this.pruefungStudent.uid]))
|
||||
|
||||
this.$fhcAlert.alertDefault(
|
||||
'success',
|
||||
'Info',
|
||||
this.$p.t('benotungstool/pruefungSaveForUid', [this.pruefungStudent.uid]),
|
||||
true
|
||||
)
|
||||
const s = this.studenten.find(s => s.uid === res.data[1]?.student_uid)
|
||||
|
||||
s.freigabedatum = this.parseDate(res.data[1]?.['freigabedatum'])
|
||||
@@ -1357,7 +1378,12 @@ export const Benotungstool = {
|
||||
this.$api.call(ApiNoten.saveStudentenNoten(this.password, this.changedNoten, this.lv_id, this.sem_kurzbz))
|
||||
.then((res) => {
|
||||
if(res.meta.status === 'success') {
|
||||
this.$fhcAlert.alertWarning('Noten gespeichert')
|
||||
this.$fhcAlert.alertDefault(
|
||||
'success',
|
||||
'Info',
|
||||
'Noten gespeichert',
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
res.data.forEach(d => {
|
||||
@@ -1416,8 +1442,12 @@ export const Benotungstool = {
|
||||
this.sem_kurzbz,
|
||||
)).then(res => {
|
||||
if(res.meta.status === "success") {
|
||||
this.$fhcAlert.alertSuccess(this.$p.t('benotungstool/pruefungAngelegtAn', [dateStrFront]))
|
||||
|
||||
this.$fhcAlert.alertDefault(
|
||||
'success',
|
||||
'Info',
|
||||
this.$p.t('benotungstool/pruefungAngelegtAn', [dateStrFront]),
|
||||
true
|
||||
)
|
||||
|
||||
this.handleAddNewPruefungenResponse(res, uids)
|
||||
|
||||
@@ -1558,13 +1588,6 @@ export const Benotungstool = {
|
||||
mounted() {
|
||||
this.setupMounted()
|
||||
},
|
||||
unmounted() {
|
||||
if(this.headerEl) {
|
||||
this.headerEl.removeEventListener("shown.bs.collapse", this.handleSidebar)
|
||||
this.headerEl.removeEventListener("hidden.bs.collapse", this.handleSidebar)
|
||||
this.headerEl = null
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<bs-modal ref="modalContainerNotenImport" class="bootstrap-prompt" dialogClass="modal-lg">
|
||||
<template v-slot:title>{{$p.t('benotungstool/c4notenImportieren')}}</template>
|
||||
@@ -1672,6 +1695,23 @@ export const Benotungstool = {
|
||||
</template>
|
||||
</bs-modal>
|
||||
|
||||
<BsOffcanvas
|
||||
ref="drawer"
|
||||
placement="end"
|
||||
:backdrop="true"
|
||||
:style="{ '--bs-offcanvas-width': '600px' }"
|
||||
>
|
||||
<template #title>
|
||||
|
||||
</template>
|
||||
|
||||
<MobilityLegende/>
|
||||
|
||||
<template #footer>
|
||||
|
||||
</template>
|
||||
</BsOffcanvas>
|
||||
|
||||
<FhcOverlay :active="loading || saving"></FhcOverlay>
|
||||
|
||||
<div class="row">
|
||||
@@ -1721,7 +1761,7 @@ export const Benotungstool = {
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div id="notentable" class="row" :style="'overflow-x: auto; max-width: calc(98vw - ' + offsetLeft + 'px);'">
|
||||
<div id="notentable" class="row" :style="'overflow-x: auto;'">
|
||||
<core-filter-cmpt
|
||||
v-if="tabulatorCanBeBuilt"
|
||||
@uuidDefined="handleUuidDefined"
|
||||
@@ -1753,8 +1793,6 @@ export const Benotungstool = {
|
||||
</template>
|
||||
</core-filter-cmpt>
|
||||
</div>
|
||||
|
||||
<MobilityLegende/>
|
||||
`,
|
||||
};
|
||||
|
||||
|
||||
@@ -50698,18 +50698,18 @@ and represent the current state of research on the topic. The prescribed citatio
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'benotungstool',
|
||||
'phrase' => 'c4antrittCount',
|
||||
'phrase' => 'c4antrittCountv2',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Anzahl Prüfungsantritte',
|
||||
'text' => 'Antritte',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Number of exam attempts',
|
||||
'text' => 'Attempts',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
@@ -50735,6 +50735,26 @@ and represent the current state of research on the topic. The prescribed citatio
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'benotungstool',
|
||||
'phrase' => 'c4mobility',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Mobilität',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Mobility',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'benotungstool',
|
||||
|
||||
Reference in New Issue
Block a user