serientermin anlegen mitarbeiter; deadline overview mitarbeiter;

This commit is contained in:
Johann Hoffmann
2025-04-29 14:36:40 +02:00
parent c24a9997a9
commit 38424bc875
10 changed files with 750 additions and 166 deletions
+17 -6
View File
@@ -16,7 +16,8 @@ class Abgabetool extends Auth_Controller
'index' => self::PERM_LOGGED,
'getStudentProjektarbeitAbgabeFile' => self::PERM_LOGGED,
'Mitarbeiter' => self::PERM_LOGGED,
'Student' => self::PERM_LOGGED
'Student' => self::PERM_LOGGED,
'Deadlines' => self::PERM_LOGGED
]);
}
@@ -43,7 +44,7 @@ class Abgabetool extends Auth_Controller
'uid'=>getAuthUID(),
);
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'Abgabetool']);
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'AbgabetoolStudent']);
}
public function Mitarbeiter()
@@ -53,7 +54,17 @@ class Abgabetool extends Auth_Controller
'uid'=>getAuthUID(),
);
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'Abgabetool']);
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'AbgabetoolMitarbeiter']);
}
public function Deadlines()
{
$viewData = array(
'uid'=>getAuthUID(),
);
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'DeadlinesOverview']);
}
@@ -66,7 +77,7 @@ class Abgabetool extends Auth_Controller
$student_uid = $this->_ci->input->get('student_uid');
if (!isset($paabgabe_id) || isEmptyString($paabgabe_id) || !isset($student_uid) || isEmptyString($student_uid))
$this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general');
$this->terminateWithJsonError($this->p->t('global', 'wrongParameters'), 'general');
$this->_ci->load->model('education/Projektarbeit_model', 'ProjektarbeitModel');
@@ -88,10 +99,10 @@ class Abgabetool extends Auth_Controller
readfile($file_path); // read file content to output buffer
} else {
$this->terminateWithError('File not found');
$this->terminateWithJsonError('File not found');
}
} else {
$this->terminateWithError('Keine Zuordnung!');
$this->terminateWithJsonError('Keine Zuordnung!');
}
}
}
@@ -45,7 +45,9 @@ class Lehre extends FHCAPI_Controller
'postStudentProjektarbeitEndupload' => self::PERM_LOGGED,
'getMitarbeiterProjektarbeiten' => self::PERM_LOGGED,
'postProjektarbeitAbgabe' => self::PERM_LOGGED,
'deleteProjektarbeitAbgabe' => self::PERM_LOGGED
'deleteProjektarbeitAbgabe' => self::PERM_LOGGED,
'postSerientermin' => self::PERM_LOGGED,
'fetchDeadlines' => self::PERM_LOGGED // TODO: mitarbeiter recht prüfen
]);
$this->load->library('PhrasesLib');
@@ -556,5 +558,116 @@ class Lehre extends FHCAPI_Controller
$this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general');
}
/**
* endpoint for adding the same paabgabe for multiple projektarbeiten
* can be slow for large n since it queries twice per projektarbeit_id
*/
public function postSerientermin() {
$projektarbeit_ids = $_POST['projektarbeit_ids'];
$datum = $_POST['datum'];
$paabgabetyp_kurzbz = $_POST['paabgabetyp_kurzbz'];
$bezeichnung = $_POST['bezeichnung'];
$kurzbz = $_POST['kurzbz'];
if (!isset($projektarbeit_ids) || !is_array($projektarbeit_ids) || empty($projektarbeit_ids)
|| !isset($datum) || isEmptyString($datum)
|| !isset($kurzbz) || isEmptyString($kurzbz)
|| !isset($bezeichnung) || isEmptyString($bezeichnung)
|| !isset($paabgabetyp_kurzbz) || isEmptyString($paabgabetyp_kurzbz))
$this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general');
// old script checks if there already are tbl_paabgabe entries with exact date, type & kurzbz
// for each termin - good to check that in principle but should not matter in this place. if necessary
// duplicate abgabetermine can be easily deleted manually, also via cronjob@night.
// since this entry includes the kurzbz string match, it should have only ever mattered when there were
// multiple users entering the exact same set of (date, type, kurzbz) - which is a much more narrow case than the
// general "saveMultiple" function should handle
// old script afterwards again queries if user is not the zweitbetreuer of any id - this is blocked in the ui
// and should never unintentionally happen
// TODO: check berechtigung &/|| zuordnung?
$this->load->model('education/Paabgabe_model', 'PaabgabeModel');
$this->load->model('education/Projektarbeit_model', 'ProjektarbeitModel');
$res = [];
foreach ($projektarbeit_ids as $projektarbeit_id) {
$result = $this->PaabgabeModel->insert(
array(
'projektarbeit_id' => $projektarbeit_id,
'paabgabetyp_kurzbz' => $paabgabetyp_kurzbz,
'fixtermin' => false,
'datum' => $datum,
'kurzbz' => $kurzbz,
'insertvon' => getAuthUID(),
'insertamum' => date('Y-m-d H:i:s')
)
);
$data = $this->getDataOrTerminateWithError($result);
// $res[] = $data;
// send mail to student
$result = $this->ProjektarbeitModel->getStudentInfoForProjektarbeitId($projektarbeit_id);
$data = $this->getDataOrTerminateWithError($result);
// $this->addMeta('emaildata'.$projektarbeit_id, $data);
$datetime = new DateTime($datum);
$dateEmailFormatted = $datetime->format('d.m.Y');
$anredeFillString = $data[0]->anrede=="Herr"?"r":"";
$fullFormattedNameString = trim($data[0]->titelpre." ".$data[0]->vorname." ".$data[0]->nachname." ".$data[0]->titelpost);
$res[] = $fullFormattedNameString;
// Prepare mail content
$body_fields = array(
'anrede' => $data[0]->anrede,
'anredeFillString' => $anredeFillString,
'datum' => $dateEmailFormatted,
'bezeichnung' => $bezeichnung,
'fullFormattedNameString' => $fullFormattedNameString,
'kurzbz' => $kurzbz
);
$email = $data[0]->uid."@".DOMAIN;
sendSanchoMail(
'neuerTerminBachelorMasterbetreuung',
$body_fields,
$email,
$this->p->t('abgabetool', 'neuerTerminBachelorMasterbetreuung')
);
}
$this->terminateWithSuccess($res);
}
public function fetchDeadlines() {
$person_id = $_POST['person_id'];
if (!isset($person_id) || isEmptyString($person_id))
$person_id = getAuthPersonId();
if($person_id !== getAuthPersonId()) {
$this->load->library('PermissionLib');
$isAdmin = $this->permissionlib->isBerechtigt('admin');
if(!$isAdmin) $this->terminateWithError($this->p->t('ui', 'keineBerechtigung'), 'general');
}
$this->load->model('education/Paabgabe_model', 'PaabgabeModel');
$result = $this->PaabgabeModel->getDeadlines($person_id);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
}
@@ -30,5 +30,35 @@ class Paabgabe_model extends DB_Model
return $this->execQuery($qry, array($projektarbeit_id));
}
/**
* Gets all Paabgabe Termin Deadlines of zugewiesene Projektarbeiten as a Mitarbeiter for Terminübersicht Abgabetool.
* @param int $person_id
* @return object
*/
public function getDeadlines($person_id)
{
$qry = "SELECT
DISTINCT TO_CHAR(tbl_paabgabe.datum, 'DD.MM.YYYY') as datum, tbl_paabgabe.fixtermin, tbl_paabgabe.kurzbz,
person_student.vorname as stud_vorname, person_student.nachname as stud_nachname,
person_student.titelpre as stud_titelpre, person_student.titelpost as stud_titelpost,
tbl_lehrveranstaltung.semester, UPPER(tbl_studiengang.typ || tbl_studiengang.kurzbz) as stg,
tbl_paabgabetyp.bezeichnung as typ_bezeichnung
FROM
campus.tbl_paabgabe
JOIN lehre.tbl_projektarbeit USING(projektarbeit_id)
JOIN lehre.tbl_projektbetreuer USING(projektarbeit_id)
JOIN public.tbl_benutzer bn_student ON(tbl_projektarbeit.student_uid=bn_student.uid)
JOIN public.tbl_person person_student ON(bn_student.person_id=person_student.person_id)
JOIN lehre.tbl_lehreinheit ON(tbl_projektarbeit.lehreinheit_id=tbl_lehreinheit.lehreinheit_id)
JOIN lehre.tbl_lehrveranstaltung ON(tbl_lehreinheit.lehrveranstaltung_id=tbl_lehrveranstaltung.lehrveranstaltung_id)
JOIN public.tbl_studiengang ON(tbl_lehrveranstaltung.studiengang_kz=tbl_studiengang.studiengang_kz)
JOIN campus.tbl_paabgabetyp USING(paabgabetyp_kurzbz)
WHERE
tbl_projektbetreuer.person_id= ? AND tbl_paabgabe.datum>=now() AND bn_student.aktiv
ORDER BY datum";
return $this->execReadOnlyQuery($qry, array($person_id));
}
}
@@ -212,7 +212,11 @@ class Projektarbeit_model extends DB_Model
return $this->execReadOnlyQuery($qry, array($studentUID, $maUID));
}
/**
* Get a List of Projektarbeiten of a mitarbeiter with zuordnung
* used by the mitarbeiter cis4 abgabetool.
*/
public function getMitarbeiterProjektarbeiten($uid, $showAll){
$qry = "SELECT
*
@@ -242,4 +246,19 @@ class Projektarbeit_model extends DB_Model
return $this->execReadOnlyQuery($qry, array($uid));
}
/**
* Fetch Student info relevant to a projektarbeit_id
*/
public function getStudentInfoForProjektarbeitId($projektarbeit_id) {
$qry = "SELECT *
FROM campus.vw_student
WHERE uid IN(
SELECT student_uid
FROM lehre.tbl_projektarbeit
WHERE projektarbeit_id = ? )";
return $this->execReadOnlyQuery($qry, array($projektarbeit_id));
}
}
+16
View File
@@ -76,6 +76,22 @@ export default {
}
const url = '/api/frontend/v1/Lehre/deleteProjektarbeitAbgabe';
return this.$fhcApi.post(url, payload, null)
},
postSerientermin(datum, paabgabetyp_kurzbz, bezeichnung, kurzbz, projektarbeit_ids) {
const payload = {
datum, paabgabetyp_kurzbz, bezeichnung, kurzbz, projektarbeit_ids
}
const url = '/api/frontend/v1/Lehre/postSerientermin';
return this.$fhcApi.post(url, payload, null)
},
fetchDeadlines(person_id) {
const payload = {
person_id
}
const url = '/api/frontend/v1/Lehre/fetchDeadlines';
return this.$fhcApi.post(url, payload, null)
}
}
+7
View File
@@ -12,6 +12,7 @@ import Info from "../../components/Cis/Mylv/Semester/Studiengang/Lv/Info.js";
import RoomInformation, {DEFAULT_MODE_RAUMINFO} from "../../components/Cis/Mylv/RoomInformation.js";
import AbgabetoolStudent from "../../components/Cis/Abgabetool/AbgabetoolStudent.js";
import AbgabetoolMitarbeiter from "../../components/Cis/Abgabetool/AbgabetoolMitarbeiter.js";
import DeadlineOverview from "../../components/Cis/Abgabetool/DeadlineOverview.js";
@@ -44,6 +45,12 @@ const router = VueRouter.createRouter({
component: AbgabetoolMitarbeiter,
props: true
},
{
path: `/Cis/Abgabetool/Deadlines/:person_uid_prop?`,
name: 'DeadlineOverview',
component: DeadlineOverview,
props: true
},
{
path: `/Cis/Raumsuche`,
name: 'Raumsuche',
@@ -19,6 +19,7 @@ export const AbgabeMitarbeiterDetail = {
},
data() {
return {
oldPaBeurteilungLink: 'https://moodle.technikum-wien.at/mod/page/view.php?id=1005052', // TODO: inject from app & app provide link from config
eidAkzeptiert: false,
enduploadTermin: null,
allActiveLanguages: FHC_JS_DATA_STORAGE_OBJECT.server_languages,
@@ -44,16 +45,7 @@ export const AbgabeMitarbeiterDetail = {
paabgabetyp_kurzbz: 'enda',
bezeichnung: 'Endabgabe im Sekretariat'
}
],
form: Vue.reactive({
sprache: '',
abstract: '',
abstract_en: '',
schlagwoerter: '',
schlagwoerter_en: '',
kontrollschlagwoerter: '',
seitenanzahl: 1,
})
]
}
},
methods: {
@@ -171,21 +163,14 @@ export const AbgabeMitarbeiterDetail = {
window.open(link, '_blank')
},
openPlagiatcheck() {
// todo: hardcoded turnitin link pfui?
// todo: hardcoded turnitin link?
const link = "https://technikum-wien.turnitin.com/sso/sp/redwood/saml/5IyfmBr2OcSIaWQTKlFCGj/start"
window.open(link, '_blank')
}
},
watch: {
projektarbeit(newVal) {
// default select german if projektarbeit sprache was null
this.form.sprache = newVal.sprache ? this.allActiveLanguages.find(lang => lang.sprache == newVal.sprache) : this.allActiveLanguages.find(lang => lang.sprache == 'German')
this.form.abstract = newVal.abstract
this.form.abstract_en = newVal.abstract_en
this.form.schlagwoerter = newVal.schlagwoerter
this.form.schlagwoerter_en = newVal.schlagwoerter_en
this.form.kontrollschlagwoerter = newVal.kontrollschlagwoerter
this.form.seitenanzahl = newVal.seitenanzahl
},
openBenotung() {
const path = this.projektarbeit?.betreuerart_kurzbz == 'Zweitbegutachter' ? 'ProjektarbeitsbeurteilungZweitbegutachter' : 'ProjektarbeitsbeurteilungErstbegutachter'
const link = FHC_JS_DATA_STORAGE_OBJECT.app_root + 'index.ci.php/extensions/FHC-Core-Projektarbeitsbeurteilung/' + path
window.open(link, '_blank')
}
},
computed: {
@@ -212,28 +197,47 @@ export const AbgabeMitarbeiterDetail = {
template: `
<div v-if="projektarbeit">
<h5>{{$p.t('abgabetool/c4abgabeMitarbeiterbereich')}}</h5>
<div class="row">
<div class="col-8">
<p> {{projektarbeit?.student}}</p>
<p> {{projektarbeit?.titel}}</p>
<p v-if="projektarbeit?.zweitbegutachter"> {{projektarbeit?.zweitbegutachter}}</p>
</div>
<div class="col-4 d-flex justify-content-end">
<div>
<button :disabled="!getSemesterBenotbar && endUploadVorhanden" class="btn btn-secondary border-0" @click="openPlagiatcheck" style="margin-right: 4px;">
benoten
<i style="margin-left: 8px" class="fa-solid fa-user-check"></i>
</button>
<div class="col-4 d-flex">
<div class="col">
<div class="row">
<button :disabled="!getSemesterBenotbar || !endUploadVorhanden" class="btn btn-secondary border-0" @click="openBenotung" style="width: 80%;">
benoten
<i style="margin-left: 8px" class="fa-solid fa-user-check"></i>
</button>
</div>
<div class="row" style="width: 90%;">
<span v-if="!getSemesterBenotbar" v-html="$p.t('abgabetool/c4aeltereParbeitBenoten', oldPaBeurteilungLink)"></span>
<span v-else-if="!endUploadVorhanden">Kein Endupload vorhanden!</span>
</div>
</div>
<div class="col">
<div class="row">
<button v-if="projektarbeit?.betreuerart_kurzbz !== 'Zweitbegutachter'" class="btn btn-secondary border-0" @click="openPlagiatcheck" style="width: 80%;">
zur Plagiatsprüfung
<i style="margin-left: 8px" class="fa-solid fa-user-check"></i>
</button>
</div>
</div>
<div class="col">
<div class="row">
<button class="btn btn-secondary border-0" @click="openStudentPage" style="width: 80%;">
Studentenansicht
<i style="margin-left: 8px" class="fa-solid fa-eye"></i>
</button>
</div>
</div>
<button v-if="projektarbeit?.betreuerart_kurzbz !== 'Zweitbegutachter'" class="btn btn-secondary border-0" @click="openPlagiatcheck" style="margin-right: 4px;">
zur Plagiatsprüfung
<i style="margin-left: 8px" class="fa-solid fa-user-check"></i>
</button>
<button class="btn btn-secondary border-0" @click="openStudentPage">
Studentenansicht
<i style="margin-left: 8px" class="fa-solid fa-eye"></i>
</button>
</div>
</div>
<div id="uploadWrapper">
@@ -303,101 +307,6 @@ export const AbgabeMitarbeiterDetail = {
</div>
</div>
</div>
<bs-modal ref="modalContainerEnduploadZusatzdaten" class="bootstrap-prompt" dialogClass="modal-lg">
<template v-slot:title>
<div>
{{$p.t('abgabetool/c4enduploadZusatzdaten')}}
</div>
<div class="row mb-3 align-items-center">
<p class="ml-4 mr-4">Student UID: {{ projektarbeit?.student_uid}}</p>
</div>
<div class="row mb-3 align-items-center">
<p class="ml-4 mr-4">Titel: {{ projektarbeit?.titel }}</p>
</div>
</template>
<template v-slot:default>
<div class="row mb-3 align-items-center">
<div class="row">{{$p.t('abgabetool/c4Sprache')}}</div>
<div class="row">
<Dropdown
:style="{'width': '100%'}"
v-model="form.sprache"
:options="allActiveLanguages"
:optionLabel="getOptionLabelSprache">
</Dropdown>
</div>
</div>
<div class="row mb-3 align-items-center">
<div class="row">Kontrollierte Schlagwörter</div>
<div class="row">
<Textarea v-model="form.kontrollschlagwoerter"></Textarea>
</div>
</div>
<div class="row mb-3 align-items-center">
<div class="row">{{$p.t('abgabetool/c4schlagwoerterGer')}}</div>
<div class="row">
<Textarea v-model="form.schlagwoerter"></Textarea>
</div>
</div>
<div class="row mb-3 align-items-center">
<div class="row">{{$p.t('abgabetool/c4schlagwoerterEng')}}</div>
<div class="row">
<Textarea v-model="form.schlagwoerter_en"></Textarea>
</div>
</div>
<div class="row mb-3 align-items-center">
<div class="row">{{$p.t('abgabetool/c4abstractGer')}}</div>
<div class="row">
<Textarea v-model="form.abstract" rows="10"></Textarea>
</div>
</div>
<div class="row mb-3 align-items-center">
<div class="row">{{$p.t('abgabetool/c4abstractEng')}}</div>
<div class="row">
<Textarea v-model="form.abstract_en" rows="10"></Textarea>
</div>
</div>
<div class="row mb-3 align-items-center">
<div class="row">{{$p.t('abgabetool/c4seitenanzahl')}}</div>
<div class="row">
<InputNumber
v-model="form.seitenanzahl"
inputId="seitenanzahlInput" :min="1" :max="100000">
</InputNumber>
</div>
</div>
<div v-if="projektarbeit">
<div v-html="getEid"></div>
<div class="row">
<div class="col-9"></div>
<div class="col-2"><p>{{ $p.t('abgabetool/c4gelesenUndAkzeptiert') }}</p></div>
<div class="col-1">
<Checkbox
v-model="eidAkzeptiert"
:binary="true"
:pt="{ root: { class: 'ml-auto' }}"
>
</Checkbox>
</div>
</div>
</div>
</template>
<template v-slot:footer>
<button class="btn btn-primary" :disabled="getEnduploadErlaubt" @click="triggerEndupload">{{$p.t('ui/hochladen')}}</button>
</template>
</bs-modal>
`,
};
@@ -1,13 +1,18 @@
import {CoreFilterCmpt} from "../../../components/filter/Filter.js";
import AbgabeDetail from "./AbgabeMitarbeiterDetail.js";
import VerticalSplit from "../../verticalsplit/verticalsplit.js"
import BsModal from '../../Bootstrap/Modal.js';
export const AbgabetoolMitarbeiter = {
name: "AbgabetoolMitarbeiter",
components: {
BsModal,
CoreFilterCmpt,
AbgabeDetail,
VerticalSplit,
Dropdown: primevue.dropdown,
Textarea: primevue.textarea,
VueDatePicker
},
props: {
viewData: {
@@ -21,6 +26,39 @@ export const AbgabetoolMitarbeiter = {
},
data() {
return {
saving: false,
loading: false,
// TODO: fetch types
allAbgabeTypes: [
{
paabgabetyp_kurzbz: 'abstract',
bezeichnung: 'Entwurf'
},
{
paabgabetyp_kurzbz: 'zwischen',
bezeichnung: 'Zwischenabgabe'
},
{
paabgabetyp_kurzbz: 'note',
bezeichnung: 'Benotung'
},
{
paabgabetyp_kurzbz: 'end',
bezeichnung: 'Endupload'
},
{
paabgabetyp_kurzbz: 'enda',
bezeichnung: 'Endabgabe im Sekretariat'
}
],
serienTermin: Vue.reactive({
datum: new Date(),
bezeichnung: {
paabgabetyp_kurzbz: 'zwischen',
bezeichnung: 'Zwischenabgabe'
},
kurzbz: ''
}),
showAll: false,
tabulatorUuid: Vue.ref(0),
selectedData: [],
@@ -38,6 +76,7 @@ export const AbgabetoolMitarbeiter = {
layout: 'fitDataStretch',
placeholder: this.$p.t('global/noDataAvailable'),
selectable: true,
selectableCheck: this.selectionCheck,
columns: [
{
formatter: 'rowSelection',
@@ -59,7 +98,7 @@ export const AbgabetoolMitarbeiter = {
{title: Vue.computed(() => this.$p.t('abgabetool/c4stg')), field: 'stg', formatter: this.centeredTextFormatter, widthGrow: 2},
{title: Vue.computed(() => this.$p.t('abgabetool/c4sem')), field: 'studiensemester_kurzbz', formatter: this.centeredTextFormatter, widthGrow: 1},
{title: Vue.computed(() => this.$p.t('abgabetool/c4titel')), field: 'titel', formatter: this.centeredTextFormatter, maxWidth: 500, widthGrow: 8},
{title: Vue.computed(() => this.$p.t('abgabetool/c4beteuerart')), field: 'betreuerart_beschreibung',formatter: this.centeredTextFormatter, widthGrow: 8}
{title: Vue.computed(() => this.$p.t('abgabetool/c4betreuerart')), field: 'betreuerart_beschreibung',formatter: this.centeredTextFormatter, widthGrow: 8}
],
persistence: false,
},
@@ -74,24 +113,10 @@ export const AbgabetoolMitarbeiter = {
handler: async (e, cell) => {
if(cell.getColumn().getField() === "details") {
this.setDetailComponent(cell.getValue())
this.undoSelection(cell)
} else if (cell.getColumn().getField() === "mail") {
this.undoSelection(cell)
}
e.stopPropagation()
}
},
{
event: "rowClick",
handler: async (e, row) => {
e.stopPropagation()
}
},
{
event: "rowSelected",
handler: async (row) => {
}
},
{
@@ -103,16 +128,82 @@ export const AbgabetoolMitarbeiter = {
]};
},
methods: {
getOptionLabelAbgabetyp(option){
return option.bezeichnung
},
formatDate(dateParam) {
const date = new Date(dateParam)
// handle missing leading 0
const padZero = (num) => String(num).padStart(2, '0');
const month = padZero(date.getMonth() + 1); // Months are zero-based
const day = padZero(date.getDate());
const year = date.getFullYear();
return `${day}.${month}.${year}`;
},
undoSelection(cell) {
// checks if cells row is selected and unselects -> imitates columns which dont trigger row selection
// but actually just revert it after the fact
const row = cell.getRow()
if(row.isSelected()) {
row.deselect();
}
},
selectionCheck(row) {
const data = row.getData()
if(data?.betreuerart_kurzbz == 'Zweitbegutachter') return false
return true
},
showDeadlines(){
// TODO: open seperate view in new window containing all future deadlines for the employee
const link = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router
+ '/Cis/Abgabetool/Deadlines'
window.open(link, '_blank')
},
toggleShowAll(showall) {
this.showAll = showall
// TODO: debug tabulator row render
this.loadProjektarbeiten(showall, () => { this.$refs.abgabeTable?.tabulator.redraw(true) })
this.loading = true
this.loadProjektarbeiten(showall, () => {
this.$refs.abgabeTable?.tabulator.redraw(true)
this.$refs.abgabeTable?.tabulator.setSort([]);
this.loading = false
})
},
openAddSeriesModal() {
this.$refs.modalContainerAddSeries.show()
},
addSeries() {
this.saving = true
this.$fhcApi.factory.lehre.postSerientermin(
this.serienTermin.datum.toISOString(),
this.serienTermin.bezeichnung.paabgabetyp_kurzbz,
this.serienTermin.bezeichnung.bezeichnung,
this.serienTermin.kurzbz,
this.selectedData?.map(projekt => projekt.projektarbeit_id)
).then(res => {
if (res.meta.status === "success" && res.data) {
this.$fhcAlert.alertSuccess(this.$p.t('abgabetool/serienTerminGespeichert'))
// TODO: sticky lifetime erhöhen um sinnvoll lesen zu können?
this.$fhcAlert.alertInfo(this.$p.t('abgabetool/serienTerminEmailSentInfo', [this.createInfoString(res.data)]));
} else {
this.$fhcAlert.alertError(this.$p.t('abgabetool/errorSerienterminSpeichern'))
}
}).finally(()=>{
this.saving = false
})
this.$refs.modalContainerAddSeries.hide()
},
createInfoString(data) {
let str = '';
data.forEach(name => {
str += name
str += '; '
})
return str
},
isPastDate(date) {
return new Date(date) < new Date(Date.now())
@@ -283,8 +374,57 @@ export const AbgabetoolMitarbeiter = {
this.setupMounted()
},
template: `
<bs-modal ref="modalContainerAddSeries" class="bootstrap-prompt"
dialogClass="modal-lg">
<template v-slot:title>
<div>
{{ $p.t('abgabetool/addSeries') }}
</div>
</template>
<template v-slot:default>
<div class="row">
<div class="col-3 d-flex justify-content-center align-items-center">
{{$p.t('abgabetool/c4zieldatum')}}
</div>
<div class="col-3 d-flex justify-content-center align-items-center">
{{$p.t('abgabetool/c4abgabetyp')}}
</div>
<div class="col-6 d-flex justify-content-center align-items-center">
{{$p.t('abgabetool/c4abgabekurzbz')}}
</div>
</div>
<div class="row">
<div class="col-3 d-flex justify-content-center align-items-center">
<div>
<VueDatePicker
style="width: 95%;"
v-model="serienTermin.datum"
:clearable="false"
:enable-time-picker="false"
:format="formatDate"
:text-input="true"
auto-apply>
</VueDatePicker>
</div>
</div>
<div class="col-3 d-flex justify-content-center align-items-center">
<Dropdown
:style="{'width': '100%'}"
v-model="serienTermin.bezeichnung"
:options="allAbgabeTypes"
:optionLabel="getOptionLabelAbgabetyp">
</Dropdown>
</div>
<div class="col-6 d-flex justify-content-center align-items-center">
<Textarea style="margin-bottom: 4px;" v-model="serienTermin.kurzbz" rows="3" cols="40"></Textarea>
</div>
</div>
</template>
<template v-slot:footer>
<button type="button" class="btn btn-primary" @click="addSeries">{{ $p.t('global/save') }}</button>
</template>
</bs-modal>
<vertical-split ref="verticalsplit">
@@ -296,9 +436,9 @@ export const AbgabetoolMitarbeiter = {
@uuidDefined="handleUuidDefined"
ref="abgabeTable"
:newBtnShow="true"
:newBtnLabel="$p.t('global/neueTerminserie')"
:newBtnLabel="$p.t('abgabetool/neueTerminserie')"
:newBtnDisabled="!selectedData.length"
@click:new=addSeries
@click:new=openAddSeriesModal
:tabulator-options="abgabeTableOptions"
:tabulator-events="abgabeTableEventHandlers"
tableOnly
@@ -316,6 +456,14 @@ export const AbgabetoolMitarbeiter = {
<i class="fa fa-hourglass-end"></i>
{{ $p.t('abgabetool/showDeadlines') }}
</button>
<div v-show="saving">
{{ $p.t('abgabetool/currentlySaving') }} <i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
</div>
<div v-show="loading">
{{ $p.t('abgabetool/currentlyLoading') }} <i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
</div>
</template>
</core-filter-cmpt>
@@ -0,0 +1,151 @@
import {CoreFilterCmpt} from "../../../components/filter/Filter.js";
export const DeadlineOverview = {
name: "DeadlineOverview",
components: {
CoreFilterCmpt,
},
props: {
person_uid_prop: {
default: null
},
viewData: {
type: Object,
required: true,
default: () => ({name: '', uid: ''}),
validator(value) {
return value && value.name && value.uid
}
}
},
data() {
return {
fullName: null, // TODO: fetch this somewhere
deadlines: null,
tabulatorUuid: Vue.ref(0),
tableBuiltResolve: null,
tableBuiltPromise: null,
deadlineTableOptions: {
height: 700,
index: 'projektarbeit_id',
layout: 'fitColumns',
placeholder: this.$p.t('global/noDataAvailable'),
columns: [
{title: Vue.computed(() => this.$p.t('abgabetool/c4zieldatum')), field: 'datum', formatter: this.centeredTextFormatter, widthGrow: 1, tooltip: false},
{title: Vue.computed(() => this.$p.t('abgabetool/c4fixtermin')), field: 'fixterminstring', formatter: this.centeredTextFormatter, widthGrow: 1, tooltip: false},
{title: Vue.computed(() => this.$p.t('abgabetool/c4abgabetyp')), field: 'typ_bezeichnung', formatter: this.centeredTextFormatter, widthGrow: 1},
{title: Vue.computed(() => this.$p.t('abgabetool/c4abgabekurzbz')), field: 'kurzbz', formatter: this.centeredTextFormatter, widthGrow: 3},
{title: Vue.computed(() => this.$p.t('person/studentIn')), field: 'student', formatter: this.centeredTextFormatter, widthGrow: 2},
{title: Vue.computed(() => this.$p.t('abgabetool/c4stg')), field: 'stg', formatter: this.centeredTextFormatter,widthGrow: 1},
{title: Vue.computed(() => this.$p.t('abgabetool/c4sem')), field: 'semester', formatter: this.centeredTextFormatter, widthGrow: 1}
],
persistence: false,
},
deadlineTableEventHandlers: [{
event: "tableBuilt",
handler: async () => {
this.tableBuiltResolve()
}
},
{
event: "cellClick",
handler: async (e, cell) => {
if(cell.getColumn().getField() === "details") {
const val = cell.getValue()
if(val.mode === 'detailTermine') {
this.setDetailComponent(cell.getValue())
} else if (val.mode === 'beurteilungDownload') {
const pdfExportLink = FHC_JS_DATA_STORAGE_OBJECT.app_root + 'cis/private/pdfExport.php?xml=projektarbeitsbeurteilung.xml.php&xsl=Projektbeurteilung&betreuerart_kurzbz='+val.betreuerart_kurzbz+'&projektarbeit_id='+val.projektarbeit_id+'&person_id=' + val.betreuer_person_id
// const pdfExportLink2 = FHC_JS_DATA_STORAGE_OBJECT.app_root + 'cis/private/lehre/projektbeurteilungDocumentExport.php?betreuerart_kurzbz='+val.betreuerart_kurzbz+'&projektarbeit_id='+val.projektarbeit_id+'&person_id=' + val.betreuer_person_id
window.open(pdfExportLink, '_blank')
}
} else if (cell.getColumn().getField() === "beurteilung") {
const val = cell.getValue()
if(val != '-') window.open(val, '_blank')
}
e.stopPropagation()
}
}
]};
},
methods: {
centeredTextFormatter(cell) {
const val = cell.getValue()
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
'<p style="max-width: 100%; word-wrap: break-word; white-space: normal;">'+val+'</p></div>'
},
tableResolve(resolve) {
this.tableBuiltResolve = resolve
},
loadDeadlines() {
this.$fhcApi.factory.lehre.fetchDeadlines(this.person_uid_prop ?? null)
.then(res => {
if(res?.data) this.setupData(res.data)
})
},
setupData(data) {
this.deadlines = data
this.deadlines.forEach(dl => {
dl.student = (dl.stud_titelpre ? (dl.stud_titelpre + ' ') :'') + dl.stud_vorname + ' ' + dl.stud_nachname + (dl.stud_titelpost ? (' ' + dl.stud_titelpost) :'')
dl.fixterminstring = dl.fixtermin ? this.$p.t('abgabetool/c4yes') : this.$p.t('abgabetool/c4no')
})
this.$refs.deadlineTable.tabulator.setColumns(this.deadlineTableOptions.columns)
this.$refs.deadlineTable.tabulator.setData(this.deadlines);
},
handleUuidDefined(uuid) {
this.tabulatorUuid = uuid
},
calcMaxTableHeight() {
const tableID = this.tabulatorUuid ? ('-' + this.tabulatorUuid) : ''
const tableDataSet = document.getElementById('filterTableDataset' + tableID);
if(!tableDataSet) return
const rect = tableDataSet.getBoundingClientRect();
this.deadlineTableOptions.height = window.visualViewport.height - rect.top
this.$refs.deadlineTable.tabulator.setHeight(this.deadlineTableOptions.height)
},
async setupMounted() {
this.tableBuiltPromise = new Promise(this.tableResolve)
await this.tableBuiltPromise
this.loadDeadlines()
this.calcMaxTableHeight()
}
},
watch: {
},
computed: {
},
created() {
},
mounted() {
this.setupMounted()
},
template: `
<h2>{{$p.t('abgabetool/deadlinesTitle')}} {{ fullName ? ('-' + fullName) : ''}}</h2>
<hr>
<core-filter-cmpt
@uuidDefined="handleUuidDefined"
:title="''"
ref="deadlineTable"
:tabulator-options="deadlineTableOptions"
:tabulator-events="deadlineTableEventHandlers"
tableOnly
:sideMenu="false"
/>
`,
};
export default DeadlineOverview;
+181 -1
View File
@@ -30938,7 +30938,7 @@ array(
),
array(
'sprache' => 'English',
'text' => 'Wrong parameters tranferred',
'text' => 'Wrong parameters transferred',
'description' => '',
'insertvon' => 'system'
)
@@ -37879,6 +37879,66 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'neuerTerminBachelorMasterbetreuung',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Neuer Termin Bachelor-/Masterarbeitsbetreuung",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => "New date for Bachelor/Master thesis supervision",
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'neueTerminserie',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Terminserie anlegen",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => "Create recurring deadline",
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'serienTerminEmailSentInfo',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Email über neuen Abgabetermin versendet an: {0}",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => "Email about new deadline sent to: {0}",
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
@@ -39784,6 +39844,26 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'c4aeltereParbeitBenoten',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Projektarbeit für älteres Semester, bitte <a href="{0}" target="_blank">Word-Formular zur Benotung</a> verwenden!',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Thesis handed in for older semester, please <a href="{0}" target="_blank">use word form for assessment</a>!',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
@@ -39964,6 +40044,66 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'deadlinesTitle',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Terminübersicht",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => "Deadline Overview",
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'c4yes',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Ja",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => "Yes",
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'c4no',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Nein",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => "No",
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
@@ -40044,6 +40184,46 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'currentlySaving',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Speichern... ",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Saving... ',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',
'phrase' => 'currentlyLoading',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Laden... ",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Loading... ',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abgabetool',