diff --git a/application/config/stv.php b/application/config/stv.php
index e03c00084..84b148362 100644
--- a/application/config/stv.php
+++ b/application/config/stv.php
@@ -61,7 +61,11 @@ $config['tabs'] =
'notes' => [
//if true, the count of Messages will be shown in the header of the Tab Messages
'showCountNotes' => true
- ]
+ ],
+ 'combinePeople' => [
+ //multitab should only be shown with this length of selection
+ 'validCountMulti' => 2,
+ ],
];
// List of fields to show when ZGV_DOKTOR_ANZEIGEN is defined
@@ -117,5 +121,6 @@ $config['students_tab_order'] = [
'status',
'groups',
'finalexam',
+ 'combinePeople',
'archive',
];
diff --git a/application/controllers/Cis/Pub.php b/application/controllers/Cis/Pub.php
index bebc844ab..de456145b 100644
--- a/application/controllers/Cis/Pub.php
+++ b/application/controllers/Cis/Pub.php
@@ -14,7 +14,7 @@ class Pub extends Auth_Controller
{
parent::__construct(
array(
- 'bild' => ['basis/cis:r']
+ 'bild' => ['basis/cis:r', 'assistenz:r']
)
);
}
diff --git a/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php b/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php
index 86b739c90..26033908d 100644
--- a/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php
+++ b/application/controllers/api/frontend/v1/stv/Aufnahmetermine.php
@@ -298,7 +298,7 @@ class Aufnahmetermine extends FHCAPI_Controller
$reihungstestangetreten =
(isset($formData['reihungstestangetreten']) && !empty($formData['reihungstestangetreten']))
? $formData['reihungstestangetreten']
- : null;
+ : false;
$aufnahmegruppe_kurzbz =
(isset($formData['aufnahmegruppe_kurzbz']) && !empty($formData['aufnahmegruppe_kurzbz']))
? $formData['aufnahmegruppe_kurzbz']
diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php
index 97d626246..3bf48bf5b 100644
--- a/application/controllers/api/frontend/v1/stv/Config.php
+++ b/application/controllers/api/frontend/v1/stv/Config.php
@@ -33,6 +33,8 @@ class Config extends FHCAPI_Controller
{
// TODO(chris): permissions
parent::__construct([
+ 'get' => ['admin:r', 'assistenz:r'],
+ 'set' => ['admin:r', 'assistenz:r'],
'filter' => ['admin:r', 'assistenz:r'],
'student' => ['admin:r', 'assistenz:r'],
'students' => ['admin:r', 'assistenz:r']
@@ -55,6 +57,95 @@ class Config extends FHCAPI_Controller
}
/**
+ * get App config
+ */
+ public function get()
+ {
+ $this->load->model('system/Variable_model', 'VariableModel');
+ $this->load->config('stv');
+
+ $config = [];
+
+ #number_displayed_past_studiensemester
+ $result = $this->VariableModel->getVariables(getAuthUID(), ['number_displayed_past_studiensemester']);
+ $data = $this->getDataOrTerminateWithError($result);
+
+ $number_displayed_past_studiensemester_default = $this->config->item('number_displayed_past_studiensemester_default');
+
+ $config['number_displayed_past_studiensemester'] = [
+ "type" => "number",
+ "label" => $this->p->t('stv', 'settings_no_displayed_past_sem'),
+ "value" => $data['number_displayed_past_studiensemester']
+ ?? $number_displayed_past_studiensemester_default
+ ];
+
+ #font_size
+ $result = $this->VariableModel->getVariables(getAuthUID(), ['stv_font_size']);
+ $data = $this->getDataOrTerminateWithError($result);
+ $config['font_size'] = [
+ "type" => "select",
+ "label" => $this->p->t('stv', 'settings_fontsize'),
+ "value" => $data['stv_font_size'] ?? "fs_normal",
+ "options" => [
+ "fs_xx-small" => $this->p->t('stv', 'settings_fontsize_xx-small'),
+ "fs_x-small" => $this->p->t('stv', 'settings_fontsize_x-small'),
+ "fs_small" => $this->p->t('stv', 'settings_fontsize_small'),
+ "fs_normal" => $this->p->t('stv', 'settings_fontsize_normal'),
+ "fs_big" => $this->p->t('stv', 'settings_fontsize_big'),
+ "fs_huge" => $this->p->t('stv', 'settings_fontsize_huge')
+ ]
+ ];
+
+ #others
+ Events::trigger('stv_config_get', function & () use (&$config) {
+ return $config;
+ });
+
+ $this->terminateWithSuccess($config);
+ }
+
+ /**
+ * set App config
+ */
+ public function set()
+ {
+ $this->load->model('system/Variable_model', 'VariableModel');
+ $this->load->library('form_validation');
+
+ $this->form_validation->set_rules(
+ 'number_displayed_past_studiensemester',
+ $this->p->t('stv', 'settings_no_displayed_past_sem'),
+ 'required|integer'
+ );
+ $this->form_validation->set_rules(
+ 'font_size',
+ $this->p->t('stv', 'settings_fontsize'),
+ 'required|in_list[fs_xx-small,fs_x-small,fs_small,fs_normal,fs_big,fs_huge]'
+ );
+
+ Events::trigger('stv_config_validation', $this->form_validation);
+
+ if (!$this->form_validation->run())
+ $this->terminateWithValidationErrors($this->form_validation->error_array());
+
+
+ $this->VariableModel->setVariable(
+ getAuthUID(),
+ 'number_displayed_past_studiensemester',
+ $this->input->post('number_displayed_past_studiensemester')
+ );
+ $this->VariableModel->setVariable(
+ getAuthUID(),
+ 'stv_font_size',
+ $this->input->post('font_size')
+ );
+
+ Events::trigger('stv_config_set', $this->input);
+
+ $this->terminateWithSuccess();
+ }
+
+ /*
* Get the config for the student filters
*
* @return void
@@ -407,6 +498,15 @@ class Config extends FHCAPI_Controller
]
];
+ if($this->permissionlib->isBerechtigt('basis/person'))
+ {
+ $result['combinePeople'] = [
+ 'title' => $this->p->t('stv', 'tab_combine_people'),
+ 'component' => './Stv/Studentenverwaltung/Details/CombinePeople.js',
+ 'config' => $config['combinePeople']
+ ];
+ }
+
$result['kontaktieren'] = [
'title' => $this->p->t('stv', 'tab_kontaktieren'),
'component' => absoluteJsImportUrl('public/js/components/Stv/Studentenverwaltung/Details/Kontaktieren.js'),
diff --git a/application/controllers/api/frontend/v1/stv/GemeinsameStudien.php b/application/controllers/api/frontend/v1/stv/GemeinsameStudien.php
index 97dad48fd..8f3d6419a 100644
--- a/application/controllers/api/frontend/v1/stv/GemeinsameStudien.php
+++ b/application/controllers/api/frontend/v1/stv/GemeinsameStudien.php
@@ -83,7 +83,7 @@ class GemeinsameStudien extends FHCAPI_Controller
{
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
- $this->StudiensemesterModel->addOrder('studienjahr_kurzbz', 'DESC');
+ $this->StudiensemesterModel->addOrder('start', 'DESC');
$result = $this->StudiensemesterModel->load();
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
diff --git a/application/controllers/api/frontend/v1/stv/Gruppen.php b/application/controllers/api/frontend/v1/stv/Gruppen.php
index c45165b41..b10cfb328 100644
--- a/application/controllers/api/frontend/v1/stv/Gruppen.php
+++ b/application/controllers/api/frontend/v1/stv/Gruppen.php
@@ -147,7 +147,8 @@ class Gruppen extends FHCAPI_Controller
'lehre' => true,
'sichtbar' => true,
'aktiv' => true,
- 'direktinskription' => false
+ 'direktinskription' => false,
+ 'generiert' => false
]);
$data = $this->getDataOrTerminateWithError($result);
diff --git a/application/controllers/api/frontend/v1/stv/Projektarbeit.php b/application/controllers/api/frontend/v1/stv/Projektarbeit.php
index 75478332f..9cc604184 100644
--- a/application/controllers/api/frontend/v1/stv/Projektarbeit.php
+++ b/application/controllers/api/frontend/v1/stv/Projektarbeit.php
@@ -268,10 +268,6 @@ class Projektarbeit extends FHCAPI_Controller
{
$this->form_validation->set_data($formData);
- $this->form_validation->set_rules('titel', 'Titel', 'required', [
- 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Titel'])
- ]);
-
$this->form_validation->set_rules('projekttyp_kurzbz', 'Projekttyp', 'required', [
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Projekttyp'])
]);
diff --git a/application/controllers/api/frontend/v1/stv/Pruefung.php b/application/controllers/api/frontend/v1/stv/Pruefung.php
index e205c85b8..4521c2033 100644
--- a/application/controllers/api/frontend/v1/stv/Pruefung.php
+++ b/application/controllers/api/frontend/v1/stv/Pruefung.php
@@ -18,6 +18,8 @@
if (! defined('BASEPATH')) exit('No direct script access allowed');
+use \DateTime as DateTime;
+
/**
* This controller operates between (interface) the JS (GUI) and the back-end
* Provides data to the ajax get calls about addresses
@@ -111,7 +113,7 @@ class Pruefung extends FHCAPI_Controller
// Load language phrases
$this->loadPhrases([
- 'global', 'ui','lehre'
+ 'global', 'ui', 'lehre', 'exam'
]);
}
@@ -172,174 +174,11 @@ class Pruefung extends FHCAPI_Controller
*
* @param lehrveranstaltung_id, student_uid, lehreinheit_id
*
- * @return values on success
- * retval 0: pruefung inserted
- * reval 1: pruefung and zeugnisnote inserted
- * retval 2: pruefung inserted, no insert Zeugnisnote
- * (change after date of examination)
- * retval 3: pruefung of type Termin2 inserted
- * and pruefung of type Termin1 as well
- * retval 5: prueufungen Termin 2 and 1 inserted
- * and no insert Zeugnisnote (change after date of examination)
+ * @return void
*/
public function insertPruefung()
{
- $authUID = getAuthUID();
-
- $this->load->library('form_validation');
-
- $this->form_validation->set_rules('lehrveranstaltung_id', $this->p->t('lehre', 'lehrveranstaltung'), 'required', [
- 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('lehre', 'lehrveranstaltung')]),
- ]);
- $this->form_validation->set_rules('lehreinheit_id', $this->p->t('lehre', 'lehreinheit'), 'required', [
- 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('lehre', 'lehreinheit')]),
- ]);
- $this->form_validation->set_rules('pruefungstyp_kurzbz', $this->p->t('lehre', 'pruefung'), 'required', [
- 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('global', 'typ')]),
- ]);
- $this->form_validation->set_rules(
- 'datum',
- $this->p->t('global', 'datum'),
- ['is_valid_date']
- );
-
- if ($this->form_validation->run() == false)
- {
- $this->terminateWithValidationErrors($this->form_validation->error_array());
- }
-
- //calculate studiensemester_kurzbz this from lehreinheit (case newPruefung)
- $studiensemester_kurzbz = $this->input->post('studiensemester_kurzbz');
- if (!$studiensemester_kurzbz)
- {
- $this->load->model('education/Lehreinheit_model', 'LehreinheitModel');
-
- $result = $this->LehreinheitModel->load($this->input->post('lehreinheit_id'));
-
- $lehreinheit = $this->getDataOrTerminateWithError($result);
- $studiensemester_kurzbz = current($lehreinheit)->studiensemester_kurzbz;
-
- if (isError($result))
- {
- $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL);
- }
- }
-
- $result = $this->PruefungModel->insert([
- 'lehreinheit_id' => $this->input->post('lehreinheit_id'),
- 'student_uid' => $this->input->post('student_uid'),
- 'mitarbeiter_uid' => $this->input->post('mitarbeiter_uid'),
- 'datum' => $this->input->post('datum'),
- 'pruefungstyp_kurzbz' => $this->input->post('pruefungstyp_kurzbz'),
- 'note' => $this->input->post('note'),
- 'anmerkung' => $this->input->post('anmerkung'),
- 'insertamum' => date('c'),
- 'insertvon' => $authUID,
- ]);
-
- $this->getDataOrTerminateWithError($result);
-
- //check if existing zeugnisnote
- $this->load->model('education/Zeugnisnote_model', 'ZeugnisnoteModel');
-
- $result = $this->ZeugnisnoteModel->loadWhere(array(
- 'lehrveranstaltung_id' => $this->input->post('lehrveranstaltung_id'),
- 'student_uid' => $this->input->post('student_uid'),
- 'studiensemester_kurzbz' => $studiensemester_kurzbz));
-
- if (isError($result))
- {
- $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL);
- }
-
- if (!hasData($result))
- {
- //insert zeugnisnote, if not existing
- $result = $this->ZeugnisnoteModel->insert(array(
- 'lehrveranstaltung_id' => $this->input->post('lehrveranstaltung_id'),
- 'student_uid' => $this->input->post('student_uid'),
- 'studiensemester_kurzbz' => $studiensemester_kurzbz,
- 'note' => $this->input->post('note'),
- 'uebernahmedatum' => date('c'),
- 'benotungsdatum' => $this->input->post('datum'),
- 'insertamum' => date('c'),
- 'insertvon' => $authUID
- ));
-
- if (isError($result))
- {
- $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL);
- }
- $this->terminateWithSuccess(1);
- }
-
- $return_code = 0;
-
- //handling Termin1 if not existing
- if($this->input->post('pruefungstyp_kurzbz') == "Termin2")
- {
- $resultP = $this->PruefungModel->loadWhere(array(
- 'lehreinheit_id' => $this->input->post('lehreinheit_id'),
- 'student_uid' => $this->input->post('student_uid'),
- 'pruefungstyp_kurzbz' => 'Termin1'));
-
- if (isError($resultP))
- {
- $this->terminateWithError(getError($resultP), self::ERROR_TYPE_GENERAL);
- }
- if(!hasData($resultP))
- {
- //check if existing Zeugnisnote
- $this->load->model('education/Zeugnisnote_model', 'ZeugnisnoteModel');
- $this->ZeugnisnoteModel->addJoin('lehre.tbl_lehreinheit', 'lehrveranstaltung_id');
-
- $resultP = $this->ZeugnisnoteModel->loadWhere(array(
- 'lehrveranstaltung_id' => $this->input->post('lehrveranstaltung_id'),
- 'student_uid' => $this->input->input->post('student_uid'),
- 'lehre.tbl_zeugnisnote.studiensemester_kurzbz' => $studiensemester_kurzbz));
- if (isError($resultP))
- {
- $this->terminateWithError(getError($resultP), self::ERROR_TYPE_GENERAL);
- }
- if (!hasData($resultP))
- {
- $this->terminateWithError("Zeugnisnote existiert nicht", self::ERROR_TYPE_GENERAL);
- }
- $dataNote = current(getData($resultP));
-
- $resultN = $this->PruefungModel->insert([
- 'lehreinheit_id' => $this->input->post('lehreinheit_id'),
- 'student_uid' => $this->input->post('student_uid'),
- 'mitarbeiter_uid' => $this->input->post('mitarbeiter_uid'),
- 'datum' => $dataNote->benotungsdatum,
- 'pruefungstyp_kurzbz' => 'Termin1',
- 'note' => $dataNote->note,
- 'punkte' => $dataNote->punkte,
- 'anmerkung' => 'automatisiert aus Zeugnisnote erstellt',
- 'insertamum' => date('c'),
- 'insertvon' => $authUID,
- ]);
-
- if (isError($resultN)) {
- $this->terminateWithError(getError($resultN), self::ERROR_TYPE_GENERAL);
- }
- $return_code = 3;
- }
- }
-
- $note = current(getData($result));
- $uebernahmedatum = new DateTime($note->uebernahmedatum);
- $benotungsdatum = new DateTime($note->benotungsdatum);
-
- $checkDate = $uebernahmedatum === '' || $benotungsdatum > $uebernahmedatum
- ? $benotungsdatum
- : $uebernahmedatum;
-
- if ($checkDate >= $this->input->post('datum') && $note !== $note->note)
- {
- $this->terminateWithSuccess($return_code + 2);
- }
- $this->terminateWithSuccess($return_code + 2);
+ $this->insertOrUpdatePruefung();
}
/**
@@ -348,8 +187,6 @@ class Pruefung extends FHCAPI_Controller
* @param pruefung_id
*
* @return success or error
- *
- * no impact on lehre.tbl_zeugnisnote
*/
public function updatePruefung($pruefung_id)
{
@@ -359,48 +196,7 @@ class Pruefung extends FHCAPI_Controller
if (!$oldpruefung)
show_404(); // Pruefung that should be updated does not exist
- $authUID = getAuthUID();
-
- $this->load->library('form_validation');
-
- $this->form_validation->set_rules('lehrveranstaltung_id', $this->p->t('lehre', 'lehrveranstaltung'), 'required', [
- 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('lehre', 'lehrveranstaltung')]),
- ]);
- $this->form_validation->set_rules('lehreinheit_id', $this->p->t('lehre', 'lehreinheit'), 'required', [
- 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('lehre', 'lehreinheit')]),
- ]);
- $this->form_validation->set_rules('pruefungstyp_kurzbz', $this->p->t('lehre', 'pruefung'), 'required', [
- 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('global', 'typ')]),
- ]);
- $this->form_validation->set_rules(
- 'datum',
- $this->p->t('global', 'datum'),
- ['is_valid_date']
- );
-
- if ($this->form_validation->run() == false)
- {
- $this->terminateWithValidationErrors($this->form_validation->error_array());
- }
-
- $result = $this->PruefungModel->update(
- [
- 'pruefung_id' => $pruefung_id
- ],
- [ 'lehreinheit_id' => $this->input->post('lehreinheit_id'),
- 'student_uid' => $this->input->post('student_uid'),
- 'mitarbeiter_uid' => $this->input->post('mitarbeiter_uid'),
- 'note' => $this->input->post('note'),
- 'pruefungstyp_kurzbz' => $this->input->post('pruefungstyp_kurzbz'),
- 'datum' => $this->input->post('datum'),
- 'anmerkung' => $this->input->post('anmerkung'),
- 'updatevon' => $authUID,
- 'updateamum' => date('c'),
- ]
- );
- $this->getDataOrTerminateWithError($result);
-
- return $this->outputJsonSuccess(true);
+ $this->insertOrUpdatePruefung($pruefung_id);
}
/**
@@ -574,4 +370,198 @@ class Pruefung extends FHCAPI_Controller
return $this->terminateWithSuccess($data);
}
+
+ protected function insertOrUpdatePruefung($pruefung_id=null)
+ {
+ $authUID = getAuthUID();
+
+ $this->load->library('form_validation');
+
+ $this->form_validation->set_rules('lehreinheit_id', $this->p->t('lehre', 'lehreinheit'), 'required', [
+ 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('lehre', 'lehreinheit')]),
+ ]);
+ $this->form_validation->set_rules('pruefungstyp_kurzbz', $this->p->t('lehre', 'pruefung'), 'required', [
+ 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('global', 'typ')]),
+ ]);
+ $this->form_validation->set_rules(
+ 'datum',
+ $this->p->t('global', 'datum'),
+ ['is_valid_date']
+ );
+
+ if ($this->form_validation->run() == false)
+ {
+ $this->terminateWithValidationErrors($this->form_validation->error_array());
+ }
+
+ $this->load->model('education/Zeugnisnote_model', 'ZeugnisnoteModel');
+
+ $this->PruefungModel->db->trans_start();
+
+ if ($this->input->post('pruefungstyp_kurzbz') == "Termin2")
+ {
+ //Wenn ein 2. Termin angelegt wird, und kein 1. Termin vorhanden ist,
+ //dann wird auch ein 1. Termin angelegt mit der derzeitigen Zeugnisnote
+ $resultP = $this->PruefungModel->loadWhere(array(
+ 'lehreinheit_id' => $this->input->post('lehreinheit_id'),
+ 'student_uid' => $this->input->post('student_uid'),
+ 'pruefungstyp_kurzbz' => 'Termin1'));
+
+ $termin1 = $this->getDataOrTerminateWithError($resultP);
+ if (!$termin1)
+ {
+ //check if existing Zeugnisnote
+ $this->ZeugnisnoteModel->addJoin('lehre.tbl_lehreinheit', 'lehrveranstaltung_id');
+
+ $this->ZeugnisnoteModel->db->where(
+ 'lehre.tbl_zeugnisnote.studiensemester_kurzbz',
+ 'lehre.tbl_lehreinheit.studiensemester_kurzbz',
+ false
+ );
+ $resultP = $this->ZeugnisnoteModel->loadWhere(array(
+ 'lehrveranstaltung_id' => $this->input->post('lehrveranstaltung_id'),
+ 'student_uid' => $this->input->post('student_uid')
+ ));
+
+ $zeugnisnoten = $this->getDataOrTerminateWithError($resultP);
+ if ($zeugnisnoten)
+ {
+ $zeugnisnote = current($zeugnisnoten);
+
+ $resultN = $this->PruefungModel->insert([
+ 'lehreinheit_id' => $this->input->post('lehreinheit_id'),
+ 'student_uid' => $this->input->post('student_uid'),
+ 'mitarbeiter_uid' => $this->input->post('mitarbeiter_uid'),
+ 'datum' => $zeugnisnote->benotungsdatum,
+ 'pruefungstyp_kurzbz' => 'Termin1',
+ 'note' => $zeugnisnote->note,
+ 'punkte' => $zeugnisnote->punkte,
+ 'anmerkung' => 'automatisiert aus Zeugnisnote erstellt',
+ 'insertamum' => date('c'),
+ 'insertvon' => $authUID,
+ ]);
+
+ $this->getDataOrTerminateWithError($resultN);
+ }
+ //Wenn keine Zeugnisnote vorhanden ist, dann wird kein
+ //1.Termin angelegt
+ }
+ }
+
+ if(intval($pruefung_id) > 0)
+ {
+ $result = $this->PruefungModel->update(
+ [
+ 'pruefung_id' => $pruefung_id
+ ],
+ [ 'lehreinheit_id' => $this->input->post('lehreinheit_id'),
+ 'student_uid' => $this->input->post('student_uid'),
+ 'mitarbeiter_uid' => $this->input->post('mitarbeiter_uid'),
+ 'note' => $this->input->post('note'),
+ 'pruefungstyp_kurzbz' => $this->input->post('pruefungstyp_kurzbz'),
+ 'datum' => $this->input->post('datum'),
+ 'anmerkung' => $this->input->post('anmerkung'),
+ 'updatevon' => $authUID,
+ 'updateamum' => date('c'),
+ ]
+ );
+ }
+ else
+ {
+ $result = $this->PruefungModel->insert([
+ 'lehreinheit_id' => $this->input->post('lehreinheit_id'),
+ 'student_uid' => $this->input->post('student_uid'),
+ 'mitarbeiter_uid' => $this->input->post('mitarbeiter_uid'),
+ 'datum' => $this->input->post('datum'),
+ 'pruefungstyp_kurzbz' => $this->input->post('pruefungstyp_kurzbz'),
+ 'note' => $this->input->post('note'),
+ 'anmerkung' => $this->input->post('anmerkung'),
+ 'insertamum' => date('c'),
+ 'insertvon' => $authUID,
+ 'punkte' => $this->input->post('punkte') ? str_replace(',', '.', $this->input->post('punkte')) : null
+ ]);
+ }
+
+ $this->getDataOrTerminateWithError($result);
+
+ //get studiensemester_kurzbz and lehreveranstaltung_id from lehreinheit
+ $this->load->model('education/Lehreinheit_model', 'LehreinheitModel');
+
+ $result = $this->LehreinheitModel->load($this->input->post('lehreinheit_id'));
+
+ $lehreinheiten = $this->getDataOrTerminateWithError($result);
+
+ if (!$lehreinheiten) {
+ $this->terminateWithValidationErrors([
+ 'lehreinheit_id' => $this->p->t('ui', 'error_fieldNotFound', [
+ 'field' => $this->p->t('lehre', 'lehreinheit')
+ ])
+ ]);
+ }
+ $lehreinheit = current($lehreinheiten);
+ $studiensemester_kurzbz = $lehreinheit->studiensemester_kurzbz;
+ $lehrveranstaltung_id = $lehreinheit->lehrveranstaltung_id;
+
+ //check if existing zeugnisnote
+ $result = $this->ZeugnisnoteModel->loadWhere(array(
+ 'lehrveranstaltung_id' => $lehrveranstaltung_id,
+ 'student_uid' => $this->input->post('student_uid'),
+ 'studiensemester_kurzbz' => $studiensemester_kurzbz
+ ));
+
+ $zeugnisnoten = $this->getDataOrTerminateWithError($result);
+
+ if (!$zeugnisnoten)
+ {
+ //insert zeugnisnote, if not existing
+ $result = $this->ZeugnisnoteModel->insert(array(
+ 'lehrveranstaltung_id' => $lehrveranstaltung_id,
+ 'student_uid' => $this->input->post('student_uid'),
+ 'studiensemester_kurzbz' => $studiensemester_kurzbz,
+ 'note' => $this->input->post('note'),
+ 'uebernahmedatum' => date('c'),
+ 'benotungsdatum' => $this->input->post('datum'),
+ 'insertamum' => date('c'),
+ 'insertvon' => $authUID,
+ 'punkte' => $this->input->post('punkte') ? str_replace(',', '.', $this->input->post('punkte')) : null
+ ));
+
+ $this->getDataOrTerminateWithError($result);
+
+ $this->PruefungModel->db->trans_complete();
+ $this->terminateWithSuccess();
+ }
+
+ $note = current($zeugnisnoten);
+ $uebernahmedatum = new DateTime($note->uebernahmedatum);
+ $benotungsdatum = new DateTime($note->benotungsdatum);
+ $pruefungsdatum = new DateTime($this->input->post('datum'));
+
+ $checkDate = $note->uebernahmedatum === '' || $benotungsdatum > $uebernahmedatum
+ ? $benotungsdatum
+ : $uebernahmedatum;
+
+ if ($checkDate > $pruefungsdatum && $this->input->post('note') !== $note->note)
+ {
+ $this->PruefungModel->db->trans_complete();
+ $this->terminateWithSuccess($this->p->t('exam', 'hinweis_changeAfterExamDate'));
+ }
+
+ //update zeugnisnote, if existing and valid datum
+ $result = $this->ZeugnisnoteModel->update([
+ 'lehrveranstaltung_id' => $lehrveranstaltung_id,
+ 'student_uid' => $this->input->post('student_uid'),
+ 'studiensemester_kurzbz' => $studiensemester_kurzbz
+ ], [
+ 'note' => $this->input->post('note'),
+ 'uebernahmedatum' => date('c'),
+ 'benotungsdatum' => $this->input->post('datum'),
+ 'updateamum' => date('c'),
+ 'updatevon' => $authUID,
+ 'punkte' => $this->input->post('punkte') ? str_replace(',', '.', $this->input->post('punkte')) : null
+ ]);
+
+ $this->PruefungModel->db->trans_complete();
+ $this->terminateWithSuccess();
+ }
}
diff --git a/application/controllers/api/frontend/v1/stv/Students.php b/application/controllers/api/frontend/v1/stv/Students.php
index 12440f036..9dbea65f2 100644
--- a/application/controllers/api/frontend/v1/stv/Students.php
+++ b/application/controllers/api/frontend/v1/stv/Students.php
@@ -765,6 +765,86 @@ class Students extends FHCAPI_Controller
$this->terminateWithSuccess($data);
}
+ /**
+ * @param string $studiensemester_kurzbz
+ *
+ * @return void
+ */
+ public function search($studiensemester_kurzbz)
+ {
+ $this->addMeta('ci_method', __FUNCTION__);
+ $this->addMeta('ci_params', array(
+ 'studiensemester_kurzbz' => $studiensemester_kurzbz
+ ));
+
+ $this->load->library('SearchLib', [ 'config' => 'searchstv' ]);
+ $this->load->library('form_validation');
+
+ $this->form_validation->set_rules('searchstr', 'searchstr', 'required');
+ $this->form_validation->set_rules('types[]', 'types', 'required');
+
+ if (!$this->form_validation->run())
+ $this->terminateWithValidationErrors($this->form_validation->error_array());
+
+ $result = $this->searchlib->search($this->input->post('searchstr'), $this->input->post('types'));
+
+ $data = $this->getDataOrTerminateWithError($result);
+
+
+ $this->load->model('crm/Prestudent_model', 'PrestudentModel');
+
+ $this->prepareQuery($studiensemester_kurzbz);
+
+ $this->PrestudentModel->addSelect("COALESCE(v.semester::text, CASE WHEN public.get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL) IN ('Aufgenommener', 'Bewerber', 'Wartender', 'interessent') THEN public.get_absem_prestudent(tbl_prestudent.prestudent_id, NULL)::text ELSE ''::text END) AS semester", false);
+ $this->PrestudentModel->addSelect('v.verband');
+ $this->PrestudentModel->addSelect('v.gruppe');
+
+ //add status per semester
+ $this->PrestudentModel->addSelect(
+ "(
+ SELECT status_kurzbz
+ FROM public.tbl_prestudentstatus pss
+ WHERE pss.prestudent_id = public.tbl_prestudent.prestudent_id
+ AND pss.studiensemester_kurzbz = " . $this->PrestudentModel->escape($studiensemester_kurzbz) . "
+ ORDER BY GREATEST(pss.datum, '0001-01-01') DESC
+ LIMIT 1
+ ) AS statusofsemester"
+ );
+
+ $this->addSelectPrioRel();
+
+ $this->addFilter($studiensemester_kurzbz);
+
+ $prestudent_ids = [];
+ $student_uids = [];
+ $this->addMeta('data', $data);
+ foreach ($data as $row) {
+ $dataset = json_decode($row->data);
+ if ($row->type == 'prestudent') {
+ $prestudent_ids[] = $dataset->prestudent_id;
+ } elseif ($row->type == 'student') {
+ $student_uids[] = $dataset->uid;
+ }
+ }
+
+ if ($prestudent_ids && $student_uids) {
+ $this->PrestudentModel->db->where_in('tbl_prestudent.prestudent_id', $prestudent_ids);
+ $this->PrestudentModel->db->or_where_in('s.student_uid', $student_uids);
+ } elseif ($prestudent_ids) {
+ $this->PrestudentModel->db->where_in('tbl_prestudent.prestudent_id', $prestudent_ids);
+ } elseif ($student_uids) {
+ $this->PrestudentModel->db->where_in('s.student_uid', $student_uids);
+ } else {
+ $this->terminateWithSuccess([]);
+ }
+
+ $result = $this->PrestudentModel->load();
+
+ $data = $this->getDataOrTerminateWithError($result);
+
+ $this->terminateWithSuccess($data);
+ }
+
/**
* @param string|null $studiensemester_kurzbz
* @param string $type
diff --git a/application/controllers/api/frontend/v1/stv/Verband.php b/application/controllers/api/frontend/v1/stv/Verband.php
index 9fcd97c91..eb25a548b 100644
--- a/application/controllers/api/frontend/v1/stv/Verband.php
+++ b/application/controllers/api/frontend/v1/stv/Verband.php
@@ -165,7 +165,17 @@ class Verband extends FHCAPI_Controller
$this->StudiengangModel->addDistinct();
$this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", semester) AS link", false);
- $this->StudiengangModel->addSelect("CONCAT(UPPER(CONCAT(typ, kurzbz)), '-', semester, (SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END FROM public.tbl_lehrverband WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester ORDER BY verband, gruppe LIMIT 1)) AS name", false);
+ $this->StudiengangModel->addSelect("CONCAT(
+ UPPER(CONCAT(typ, kurzbz)),
+ '-',
+ semester,
+ (
+ SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END
+ FROM public.tbl_lehrverband
+ WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester
+ ORDER BY verband, gruppe LIMIT 1
+ )
+ ) AS name", false);
$this->StudiengangModel->addSelect('semester');
$this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false);
@@ -173,6 +183,7 @@ class Verband extends FHCAPI_Controller
$this->StudiengangModel->addOrder('semester');
if ($org_form !== null) {
+ $this->StudiengangModel->addSelect("v.orgform_kurzbz");
$this->StudiengangModel->db->group_start();
$this->StudiengangModel->db->where('v.semester', 0);
$this->StudiengangModel->db->or_where('v.orgform_kurzbz', $org_form);
@@ -188,6 +199,7 @@ class Verband extends FHCAPI_Controller
array_unshift($list, [
'name' => 'PreStudent',
'link' => $link . 'prestudent',
+ 'no_sem_reload' => true,
'stg_kz' => (int)$studiengang_kz,
'children' => $this->getStdSem($link . 'prestudent/', $studiengang_kz)
]);
@@ -216,7 +228,6 @@ class Verband extends FHCAPI_Controller
$list = array_merge($list, $result);
}
}
-
}
$this->terminateWithSuccess($list);
}
diff --git a/application/controllers/api/v1/person/Person.php b/application/controllers/api/v1/person/Person.php
index 6a373137f..935fbae62 100644
--- a/application/controllers/api/v1/person/Person.php
+++ b/application/controllers/api/v1/person/Person.php
@@ -233,10 +233,10 @@ class Person extends API_Controller
//Quersumme bilden
for ($i = 0; $i < 10; $i++)
{
- $erg += $gewichtung[$i] * $tmpSvnr{$i};
+ $erg += $gewichtung[$i] * $tmpSvnr[$i];
}
- if ($tmpSvnr{3} != ($erg % 11)) //Vergleichen der Pruefziffer mit Quersumme Modulo 11
+ if ($tmpSvnr[3] != ($erg % 11)) //Vergleichen der Pruefziffer mit Quersumme Modulo 11
{
return error('SVNR ist ungueltig');
}
@@ -244,7 +244,7 @@ class Person extends API_Controller
if (mb_strlen($person['svnr']) == 12)
{
$last = substr($person['svnr'], 10, 12);
- if ($last{0} != 'v' || !is_numeric($last{1}))
+ if ($last[0] != 'v' || !is_numeric($last[1]))
{
return error('SVNR ist ungueltig');
}
diff --git a/application/controllers/system/infocenter/InfoCenter.php b/application/controllers/system/infocenter/InfoCenter.php
index 1a4f566e6..eaa207ff1 100644
--- a/application/controllers/system/infocenter/InfoCenter.php
+++ b/application/controllers/system/infocenter/InfoCenter.php
@@ -22,6 +22,7 @@ class InfoCenter extends Auth_Controller
const REIHUNGSTESTABSOLVIERT_PAGE = 'reihungstestAbsolviert';
const ABGEWIESEN_PAGE = 'abgewiesen';
const AUFGENOMMEN_PAGE = 'aufgenommen';
+ const ONBOARDING_PAGE = 'onboarding';
const SHOW_DETAILS_PAGE = 'showDetails';
const SHOW_ZGV_DETAILS_PAGE = 'showZGVDetails';
const ZGV_UBERPRUEFUNG_PAGE = 'ZGVUeberpruefung';
@@ -116,6 +117,7 @@ class InfoCenter extends Auth_Controller
'index' => 'infocenter:r',
'freigegeben' => 'infocenter:r',
'abgewiesen' => 'infocenter:r',
+ 'onboarding' => 'infocenter:r',
'aufgenommen' => 'infocenter:r',
'reihungstestAbsolviert' => 'infocenter:r',
'showDetails' => 'infocenter:r',
@@ -230,6 +232,13 @@ class InfoCenter extends Auth_Controller
$this->load->view('system/infocenter/infocenterAbgewiesen.php');
}
+
+ public function onboarding()
+ {
+ $this->_setNavigationMenu(self::ONBOARDING_PAGE); // define the navigation menu for this page
+
+ $this->load->view('system/infocenter/onboarding.php');
+ }
/**
* Aufgenommene page of the InfoCenter tool
@@ -1553,6 +1562,7 @@ class InfoCenter extends Auth_Controller
$reihungstestAbsolviertLink = site_url(self::INFOCENTER_URI.'/'.self::REIHUNGSTESTABSOLVIERT_PAGE);
$abgewiesenLink = site_url(self::INFOCENTER_URI.'/'.self::ABGEWIESEN_PAGE);
$aufgenommenLink = site_url(self::INFOCENTER_URI.'/'.self::AUFGENOMMEN_PAGE);
+ $onboardingLink = site_url(self::INFOCENTER_URI.'/'.self::ONBOARDING_PAGE);
$currentFilterId = $this->input->get(self::FILTER_ID);
if (isset($currentFilterId))
@@ -1561,6 +1571,7 @@ class InfoCenter extends Auth_Controller
$reihungstestAbsolviertLink .= '?'.self::PREV_FILTER_ID.'='.$currentFilterId;
$abgewiesenLink .= '?'.self::PREV_FILTER_ID.'='.$currentFilterId;
$aufgenommenLink .= '?'.self::PREV_FILTER_ID.'='.$currentFilterId;
+ $onboardingLink .= '?'.self::PREV_FILTER_ID.'='.$currentFilterId;
}
$this->navigationlib->setSessionMenu(
@@ -1624,6 +1635,18 @@ class InfoCenter extends Auth_Controller
'', // target
40 // sort
),
+ 'ohnePrestudent' => $this->navigationlib->oneLevel(
+ 'Electronic Onboarding', // description
+ $onboardingLink, // link
+ null, // children
+ 'users', // icon
+ null, // subscriptDescription
+ false, // expand
+ null, // subscriptLinkClass
+ null, // subscriptLinkValue
+ '', // target
+ 50 // sort
+ ),
)
);
}
@@ -1650,6 +1673,8 @@ class InfoCenter extends Auth_Controller
$link = site_url(self::ZGV_UEBERPRUEFUNG_URI);
if ($origin_page === self::ABGEWIESEN_PAGE)
$link = site_url(self::INFOCENTER_URI.'/'.self::ABGEWIESEN_PAGE);
+ if ($origin_page === self::ONBOARDING_PAGE)
+ $link = site_url(self::INFOCENTER_URI.'/'.self::ONBOARDING_PAGE);
if ($origin_page === self::AUFGENOMMEN_PAGE)
$link = site_url(self::INFOCENTER_URI.'/'.self::AUFGENOMMEN_PAGE);
@@ -1691,6 +1716,7 @@ class InfoCenter extends Auth_Controller
$freigegebenLink = site_url(self::INFOCENTER_URI.'/'.self::FREIGEGEBEN_PAGE);
$absolviertLink = site_url(self::INFOCENTER_URI.'/'.self::REIHUNGSTESTABSOLVIERT_PAGE);
$abgewiesenLink = site_url(self::INFOCENTER_URI.'/'.self::ABGEWIESEN_PAGE);
+ $onboardingLink = site_url(self::INFOCENTER_URI.'/'.self::ONBOARDING_PAGE);
$prevFilterId = $this->input->get(self::PREV_FILTER_ID);
if (isset($prevFilterId))
{
@@ -1767,6 +1793,24 @@ class InfoCenter extends Auth_Controller
)
);
}
+ if($page == self::ONBOARDING_PAGE)
+ {
+ $this->navigationlib->setSessionElementMenu(
+ 'onboarding',
+ $this->navigationlib->oneLevel(
+ 'Electronic Onboarding', // description
+ $onboardingLink, // link
+ null, // children
+ 'users', // icon
+ null, // subscriptDescription
+ false, // expand
+ null, // subscriptLinkClass
+ null, // subscriptLinkValue
+ '', // target
+ 50 // sort
+ )
+ );
+ }
}
/**
diff --git a/application/views/Studentenverwaltung.php b/application/views/Studentenverwaltung.php
index 01e611657..1cd28d735 100644
--- a/application/views/Studentenverwaltung.php
+++ b/application/views/Studentenverwaltung.php
@@ -22,7 +22,8 @@
'public/css/components/function.css'
],
'customJSs' => [
- 'vendor/vuejs/vuedatepicker_js/vue-datepicker.iife.js'
+ 'vendor/vuejs/vuedatepicker_js/vue-datepicker.iife.js',
+ 'vendor/moment/luxonjs/luxon.min.js'
#'vendor/npm-asset/primevue/tree/tree.min.js',
#'vendor/npm-asset/primevue/toast/toast.min.js'
],
@@ -53,6 +54,8 @@ $configArray = [
active-addons="= defined('ACTIVE_ADDONS') ? ACTIVE_ADDONS : ''; ?>"
stv-root="= site_url('Studentenverwaltung'); ?>"
cis-root="= CIS_ROOT; ?>"
+ avatar-url="= site_url('Cis/Pub/bild/person/' . getAuthPersonId()); ?>"
+ logout-url="= site_url('Cis/Auth/logout'); ?>"
:permissions="= htmlspecialchars(json_encode($permissions)); ?>"
:config="= htmlspecialchars(json_encode($configArray)); ?>"
>
diff --git a/application/views/system/infocenter/onboarding.php b/application/views/system/infocenter/onboarding.php
new file mode 100644
index 000000000..1f5bae847
--- /dev/null
+++ b/application/views/system/infocenter/onboarding.php
@@ -0,0 +1,47 @@
+load->view(
+ 'templates/FHC-Header',
+ array(
+ 'title' => 'Info Center',
+ 'jquery3' => true,
+ 'jqueryui1' => true,
+ 'jquerycheckboxes1' => true,
+ 'bootstrap3' => true,
+ 'fontawesome4' => true,
+ 'sbadmintemplate3' => true,
+ 'tablesorter2' => true,
+ 'ajaxlib' => true,
+ 'filterwidget' => true,
+ 'navigationwidget' => true,
+ 'dialoglib' => true,
+ 'phrases' => array(
+ 'person' => array('vorname', 'nachname'),
+ 'ui' => array('bitteEintragWaehlen')
+ ),
+ 'customCSSs' => array('public/css/sbadmin2/tablesort_bootstrap.css', 'public/css/infocenter/infocenterPersonDataset.css'),
+ 'customJSs' => array('public/js/bootstrapper.js', 'public/js/infocenter/rueckstellung.js', 'public/js/infocenter/infocenterPersonDataset.js')
+ )
+ );
+?>
+
+
+
+ widgetlib->widget('NavigationWidget'); ?>
+
+
+
+
+
+ load->view('system/infocenter/onboardingData.php'); ?>
+
+
+
+
+
+load->view('templates/FHC-Footer'); ?>
diff --git a/application/views/system/infocenter/onboardingData.php b/application/views/system/infocenter/onboardingData.php
new file mode 100644
index 000000000..5ee66fdde
--- /dev/null
+++ b/application/views/system/infocenter/onboardingData.php
@@ -0,0 +1,116 @@
+>0 as bezeichnung
+ FROM public.tbl_rueckstellung
+ JOIN public.tbl_rueckstellung_status USING(status_kurzbz)
+ JOIN public.tbl_person sp ON tbl_rueckstellung.person_id = sp.person_id
+ WHERE tbl_rueckstellung.rueckstellung_id =
+ (
+ SELECT srueck.rueckstellung_id
+ FROM public.tbl_rueckstellung srueck
+ WHERE srueck.person_id = tbl_rueckstellung.person_id
+ AND datum_bis >= NOW()
+ ORDER BY srueck.datum_bis DESC LIMIT 1
+ )
+ ) rueck ON rueck.person_id = p.person_id
+ WHERE p.person_id NOT IN (SELECT person_id FROM public.tbl_prestudent)';
+
+ $filterWidgetArray = array(
+ 'query' => $query,
+ 'app' => InfoCenter::APP,
+ 'datasetName' => 'onboarding',
+ 'filter_id' => $this->input->get('filter_id'),
+ 'requiredPermissions' => 'infocenter',
+ 'datasetRepresentation' => 'tablesorter',
+ 'checkboxes' => 'PersonId',
+ 'additionalColumns' => array('Details'),
+ 'columnsAliases' => array(
+ 'PersonId',
+ ucfirst($this->p->t('person', 'vorname')) ,
+ ucfirst($this->p->t('person', 'nachname')),
+ ucfirst($this->p->t('global', 'sperrdatum')),
+ ucfirst($this->p->t('global', 'gesperrtVon')),
+ ucfirst($this->p->t('infocenter', 'rueckstelldatum')),
+ ucfirst($this->p->t('infocenter', 'rueckstellgrund')),
+ ),
+
+ 'formatRow' => function($datasetRaw) {
+ /* NOTE: Dont use $this here for PHP Version compatibility */
+ $datasetRaw->{'Details'} = sprintf(
+ 'Details',
+ site_url('system/infocenter/InfoCenter/showDetails'),
+ $datasetRaw->{'PersonId'},
+ 'onboarding',
+ (isset($_GET['fhc_controller_id']) ? $_GET['fhc_controller_id'] : ''),
+ (isset($_GET['filter_id']) ? $_GET['filter_id'] : '')
+ );
+
+ if ($datasetRaw->{'LockDate'} == null)
+ {
+ $datasetRaw->{'LockDate'} = '-';
+ }
+
+ if ($datasetRaw->{'LockUser'} == null)
+ {
+ $datasetRaw->{'LockUser'} = '-';
+ }
+
+ if ($datasetRaw->{'HoldDate'} == null)
+ {
+ $datasetRaw->{'HoldDate'} = '-';
+ }
+ else
+ {
+ $datasetRaw->{'HoldDate'} = date_format(date_create($datasetRaw->{'HoldDate'}), 'Y-m-d H:i');
+ }
+
+ if ($datasetRaw->{'Rueckstellgrund'} === null)
+ {
+ $datasetRaw->{'Rueckstellgrund'} = '-';
+ }
+
+ return $datasetRaw;
+ },
+
+ 'markRow' => function($datasetRaw) {
+
+ if ($datasetRaw->LockDate != null)
+ {
+ return FilterWidget::DEFAULT_MARK_ROW_CLASS;
+ }
+ }
+
+
+
+ );
+
+ echo $this->widgetlib->widget('FilterWidget', $filterWidgetArray);
+?>
diff --git a/content/statistik/notenspiegel.php b/content/statistik/notenspiegel.php
index 1a7651296..0901b834f 100644
--- a/content/statistik/notenspiegel.php
+++ b/content/statistik/notenspiegel.php
@@ -62,6 +62,11 @@ if(!$rechte->isBerechtigt('student/noten',$studiengang_kz, 's'))
$semester = isset($_GET['semester'])?$_GET['semester']:'';
$typ = isset($_GET['typ'])?$_GET['typ']:'';
+if(isset($_GET['studiensemester']) && preg_match('/[WS]S[0-9]{4}/', $_GET['studiensemester']))
+{
+ $semester_aktuell = $_GET['studiensemester'];
+}
+
if($semester=='')
die('Bitte ein Semester auswaehlen');
diff --git a/content/statistik/notenspiegel_erweitert.php b/content/statistik/notenspiegel_erweitert.php
index 2849a1895..67097ed22 100644
--- a/content/statistik/notenspiegel_erweitert.php
+++ b/content/statistik/notenspiegel_erweitert.php
@@ -64,6 +64,11 @@ if (!$rechte->isBerechtigt('student/noten', $studiengang_kz, 's'))
$semester = isset($_GET['semester']) ? $_GET['semester'] : '';
$typ = isset($_GET['typ']) ? $_GET['typ'] : '';
+if(isset($_GET['studiensemester']) && preg_match('/[WS]S[0-9]{4}/', $_GET['studiensemester']))
+{
+ $semester_aktuell = $_GET['studiensemester'];
+}
+
if ($semester == '')
die('Bitte ein Semester auswaehlen');
diff --git a/include/File/CSV.php b/include/File/CSV.php
index c4c4d44ad..ea67181f1 100644
--- a/include/File/CSV.php
+++ b/include/File/CSV.php
@@ -178,7 +178,7 @@ class File_CSV
return $field;
}
- if ($quote && $field{0} == $quote && $field{strlen($field)-1} == $quote) {
+ if ($quote && $field[0] == $quote && $field[strlen($field) - 1] == $quote) {
return substr($field, 1, -1);
}
return $field;
@@ -230,7 +230,7 @@ class File_CSV
} elseif ($c == "\n" || $c == "\r") {
$sub = ($prev == "\r") ? 2 : 1;
if ((strlen($buff) >= $sub) &&
- ($buff{strlen($buff) - $sub} == $quote))
+ ($buff[strlen($buff) - $sub] == $quote))
{
$in_quote = false;
}
@@ -312,9 +312,9 @@ class File_CSV
$last =& $fields[count($fields) - 1];
// Fallback to read the line with readQuoted when guess
// that the simple explode won't work right
- if (($last{strlen($last) - 1} == "\n"
- && $last{0} == $conf['quote']
- && $last{strlen(rtrim($last)) - 1} != $conf['quote'])
+ if (($last[strlen($last) - 1] == "\n"
+ && $last[0] == $conf['quote']
+ && $last[strlen(rtrim($last)) - 1] != $conf['quote'])
||
(count($fields) != $conf['fields'])
// XXX perhaps there is a separator inside a quoted field
@@ -511,4 +511,4 @@ class File_CSV
return true;
}
}
-?>
\ No newline at end of file
+?>
diff --git a/include/File/Util.php b/include/File/Util.php
index 941c61441..5474bc2a7 100644
--- a/include/File/Util.php
+++ b/include/File/Util.php
@@ -96,7 +96,7 @@ class File_Util
{
if (File_Util::isAbsolute($path)) {
if (FILE_WIN32) {
- return substr($path, $path{3} == '\\' ? 4 : 3);
+ return substr($path, $path[3] == '\\' ? 4 : 3);
}
return ltrim($path, '/');
}
@@ -182,7 +182,7 @@ class File_Util
if (FILE_WIN32) {
return preg_match('/^[a-zA-Z]:(\\\|\/)/', $path);
}
- return ($path{0} == '/') || ($path{0} == '~');
+ return ($path[0] == '/') || ($path[0] == '~');
}
/**
@@ -244,11 +244,11 @@ class File_Util
} else {
$cwd = getcwd();
$drive = substr($cwd, 0, 2);
- if ($path{0} !== $separator{0}) {
+ if ($path[0] !== $separator[0]) {
$path = substr($cwd, 3) . $separator . $path;
}
}
- } elseif ($path{0} !== $separator) {
+ } elseif ($path[0] !== $separator) {
$path = getcwd() . $separator . $path;
}
@@ -323,7 +323,7 @@ class File_Util
$entries = array();
for ($dir = dir($path); false !== $entry = $dir->read(); ) {
- if ($list & FILE_LIST_DOTS || $entry{0} !== '.') {
+ if ($list & FILE_LIST_DOTS || $entry[0] !== '.') {
$isRef = ($entry === '.' || $entry === '..');
$isDir = $isRef || is_dir($path .'/'. $entry);
if ( ((!$isDir && $list & FILE_LIST_FILES) ||
diff --git a/include/filter.class.php b/include/filter.class.php
index c3d1d6ac1..7100e6562 100644
--- a/include/filter.class.php
+++ b/include/filter.class.php
@@ -240,7 +240,7 @@ class filter extends basis_db
{
//$value->value = preg_replace('/(.*?)selected=.selected./', '$1', $value->value);
//$value->value = preg_replace('/(.*?)\s*[selected=?selected?]/', '$1', $value->value);
- //$value->value = preg_replace('/(.*?)\s*selected="selected"\s*/', '${1}', $value->value);
+ //$value->value = preg_replace('/(.*?)\s*selected="selected"\s*/', '$[1]', $value->value);
//$value->value = preg_replace('/^\s*selected=.*?selected.*?\s*/', ' ', $value->value);
//$value->value = str_replace('selected=', '', $value->value);
diff --git a/include/securimage/WavFile.php b/include/securimage/WavFile.php
index 6d84fc725..d56dbd942 100644
--- a/include/securimage/WavFile.php
+++ b/include/securimage/WavFile.php
@@ -1532,7 +1532,7 @@ class WavFile
} else {
// replace
for ($i = 0; $i < $sampleBytes; ++$i) {
- $this->_samples{$offset + $i} = $sampleBinary{$i};
+ $this->_samples[$offset + $i] = $sampleBinary[$i];
}
}
diff --git a/include/securimage/securimage.php b/include/securimage/securimage.php
index 51d876672..820e8b92f 100644
--- a/include/securimage/securimage.php
+++ b/include/securimage/securimage.php
@@ -1435,7 +1435,7 @@ class Securimage
$length = strlen($code['display']);
for($i = 0; $i < $length; ++$i) {
- $letter = $code['display']{$i};
+ $letter = $code['display'][$i];
$letters[] = $letter;
}
}
diff --git a/public/css/Cis4/Cis.css b/public/css/Cis4/Cis.css
index ff1b181dd..2bb467048 100644
--- a/public/css/Cis4/Cis.css
+++ b/public/css/Cis4/Cis.css
@@ -407,6 +407,7 @@ html {
background-color: var(--fhc-background);
border-color: var(--fhc-border);
padding: var(--fhc-cis-main-py) var(--fhc-cis-main-px);
+ min-width: 0; /* fix flex-grow with tabulator exceeding width */
}
#cis-main .fa-arrow-up-right-from-square {
@@ -854,4 +855,4 @@ html {
#cis-main .modal-footer {
background-color: var(--fhc-secondary);
-}
\ No newline at end of file
+}
diff --git a/public/css/Studentenverwaltung.css b/public/css/Studentenverwaltung.css
index 56e99b937..eb6becc15 100644
--- a/public/css/Studentenverwaltung.css
+++ b/public/css/Studentenverwaltung.css
@@ -11,6 +11,24 @@
html {
font-size: .875em;
}
+html.fs_xx-small {
+ font-size: .5em;
+}
+html.fs_x-small {
+ font-size: .625em;
+}
+html.fs_small {
+ font-size: .75em;
+}
+html.fs_normal {
+ font-size: .875em;
+}
+html.fs_big {
+ font-size: 1em;
+}
+html.fs_huge {
+ font-size: 1.125em;
+}
#appMenu {
width: 300px;
@@ -43,6 +61,12 @@ html {
flex: 1 1 auto;
}
+#nav-user-btn img {
+ object-fit: contain;
+ height: 2.5rem;
+ width: 2.5rem;
+}
+
.tabulator-row.disabled.tabulator-row-odd .tabulator-cell {
color: var(--gray-400);
}
@@ -160,4 +184,4 @@ html {
.tiny-90 div.tox.tox-tinymce {
height: 90% !important;
-}
\ No newline at end of file
+}
diff --git a/public/css/components/AppMenu.css b/public/css/components/AppMenu.css
index b980c1efc..e142858f8 100644
--- a/public/css/components/AppMenu.css
+++ b/public/css/components/AppMenu.css
@@ -16,11 +16,15 @@
padding: .5rem 1rem;
text-decoration: none;
}
+.fhc-app-menu li a.disabled {
+ --bs-link-opacity: .5;
+}
.fhc-app-menu li a.active,
.fhc-app-menu li a:hover {
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
background: var(--surface-hover);
}
+.fhc-app-menu li a.disabled,
.fhc-app-menu li a.active {
pointer-events: none;
}
diff --git a/public/js/api/factory/stv/config.js b/public/js/api/factory/stv/config.js
new file mode 100644
index 000000000..c54b2f8b2
--- /dev/null
+++ b/public/js/api/factory/stv/config.js
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2025 fhcomplete.org
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+export default {
+ get() {
+ return {
+ method: 'get',
+ url: 'api/frontend/v1/stv/config/get'
+ };
+ },
+ set(params) {
+ return {
+ method: 'post',
+ url: 'api/frontend/v1/stv/config/set',
+ params
+ };
+ }
+};
\ No newline at end of file
diff --git a/public/js/api/factory/stv/students.js b/public/js/api/factory/stv/students.js
index 07d4453d8..cae2f31b2 100644
--- a/public/js/api/factory/stv/students.js
+++ b/public/js/api/factory/stv/students.js
@@ -46,6 +46,14 @@ export default {
url: url
};
},
+ search(params, studiensemester_kurzbz) {
+ return {
+ method: 'post',
+ url: 'api/frontend/v1/stv/students/search/'
+ + encodeURIComponent(studiensemester_kurzbz),
+ params
+ };
+ },
verband(relative_path) {
return {
method: 'get',
diff --git a/public/js/apps/Studentenverwaltung.js b/public/js/apps/Studentenverwaltung.js
index 5eda16dd6..e6f77d5f5 100644
--- a/public/js/apps/Studentenverwaltung.js
+++ b/public/js/apps/Studentenverwaltung.js
@@ -148,6 +148,44 @@ const router = VueRouter.createRouter({
next();
}
},
+ {
+ name: 'search',
+ path: `/${ciPath}/studentenverwaltung/:studiensemester_kurzbz/search/:searchstr`,
+ component: FhcStudentenverwaltung,
+ props(route) {
+ return {
+ url_studiensemester_kurzbz: route.params.studiensemester_kurzbz,
+ url_mode: 'search',
+ url_prestudent_id: route.params.searchstr
+ };
+ },
+ beforeEnter(to, from, next) {
+ const isSemester = /^[WS]S\d{4}$/.test(to.params.studiensemester_kurzbz);
+ if (!isSemester) {
+ return next({name: 'index'});
+ }
+ next();
+ }
+ },
+ {
+ name: 'search_w_types',
+ path: `/${ciPath}/studentenverwaltung/:studiensemester_kurzbz/search/:types/:searchstr`,
+ component: FhcStudentenverwaltung,
+ props(route) {
+ return {
+ url_studiensemester_kurzbz: route.params.studiensemester_kurzbz,
+ url_mode: 'search',
+ url_prestudent_id: route.params.type + '/' + route.params.searchstr
+ };
+ },
+ beforeEnter(to, from, next) {
+ const isSemester = /^[WS]S\d{4}$/.test(to.params.studiensemester_kurzbz);
+ if (!isSemester) {
+ return next({name: 'index'});
+ }
+ next();
+ }
+ },
{
path: '/:pathMatch(.*)*',
redirect: {
diff --git a/public/js/components/AppConfig.js b/public/js/components/AppConfig.js
new file mode 100644
index 000000000..b6b6aaeac
--- /dev/null
+++ b/public/js/components/AppConfig.js
@@ -0,0 +1,135 @@
+/**
+ * Copyright (C) 2025 fhcomplete.org
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+import BsModal from "./Bootstrap/Modal.js";
+import FhcForm from "./Form/Form.js";
+import FormInput from "./Form/Input.js";
+
+
+export default {
+ name: 'AppConfig',
+ components: {
+ BsModal,
+ FhcForm,
+ FormInput
+ },
+ emits: [
+ 'update:modelValue'
+ ],
+ props: {
+ modelValue: {
+ type: Object,
+ required: true
+ },
+ endpoints: {
+ type: Object,
+ required: true
+ }
+ },
+ data() {
+ return {
+ setup: {},
+ tempValues: {}
+ };
+ },
+ watch: {
+ '$p.user_language.value'(n, o) {
+ if (n !== o && o !== undefined && Object.keys(this.setup).length) {
+ this.$api
+ .call(this.endpoints.get())
+ .then(res => {
+ this.setup = {};
+ Object.keys(res.data).forEach(key => {
+ const binding = { ...res.data[key] };
+ delete binding.value;
+ delete binding.options;
+ const options = res.data[key].options;
+ this.setup[key] = {
+ binding,
+ options
+ };
+ });
+ })
+ .catch(this.$fhcAlert.handleSystemErrors);
+ }
+ }
+
+ },
+ methods: {
+ update() {
+ this.$refs.form
+ .call(this.endpoints.set(this.tempValues))
+ .then(() => {
+ this.$emit('update:modelValue', { ...this.tempValues });
+ this.$refs.modal.hide();
+ this.$fhcAlert.alertSuccess(this.$p.t('ui/settings_saved'));
+ })
+ .catch(this.$fhcAlert.handleSystemErrors);
+ }
+ },
+ created() {
+ this.$api
+ .call(this.endpoints.get())
+ .then(res => {
+ Object.keys(res.data).forEach(key => {
+ const binding = { ...res.data[key] };
+ delete binding.value;
+ delete binding.options;
+ const options = res.data[key].options;
+ this.tempValues[key] = res.data[key].value;
+ this.setup[key] = {
+ binding,
+ options
+ };
+ });
+ this.$emit('update:modelValue', { ...this.tempValues });
+ })
+ .catch(this.$fhcAlert.handleSystemErrors);
+ },
+ template: /* html */`
+
+
+ {{ $p.t('ui/settings') }}
+
+
+
+
+
+
+
+
+
+
+
+ `
+};
diff --git a/public/js/components/AppMenu.js b/public/js/components/AppMenu.js
index 33d35f8df..9e85debcd 100644
--- a/public/js/components/AppMenu.js
+++ b/public/js/components/AppMenu.js
@@ -64,5 +64,6 @@ export default {
{{ menu.description }}
+
`
};
diff --git a/public/js/components/Calendar/Base/Grid.js b/public/js/components/Calendar/Base/Grid.js
index c232dd955..3418a9151 100644
--- a/public/js/components/Calendar/Base/Grid.js
+++ b/public/js/components/Calendar/Base/Grid.js
@@ -316,7 +316,7 @@ export default {
template: /* html */`
",
dataTreeChildIndent: 15,
dataTreeStartExpanded: false,
- persistenceID: 'core-message',
+ persistenceID: 'core-message-2025112401',
locale: 'de',
"langs": {
"de":{ //German language definition
diff --git a/public/js/components/Stv/Studentenverwaltung.js b/public/js/components/Stv/Studentenverwaltung.js
index a1e38875d..e3a750e0c 100644
--- a/public/js/components/Stv/Studentenverwaltung.js
+++ b/public/js/components/Stv/Studentenverwaltung.js
@@ -16,8 +16,10 @@
*/
import CoreSearchbar from "../searchbar/searchbar.js";
+import NavLanguage from "../navigation/Language.js";
import VerticalSplit from "../verticalsplit/verticalsplit.js";
import AppMenu from "../AppMenu.js";
+import AppConfig from "../AppConfig.js";
import StvVerband from "./Studentenverwaltung/Verband.js";
import StvList from "./Studentenverwaltung/List.js";
import StvDetails from "./Studentenverwaltung/Details.js";
@@ -26,14 +28,17 @@ import StvStudiensemester from "./Studentenverwaltung/Studiensemester.js";
import ApiSearchbar from "../../api/factory/searchbar.js";
import ApiStv from "../../api/factory/stv.js";
import ApiStvVerband from '../../api/factory/stv/verband.js';
+import ApiStvConfig from '../../api/factory/stv/config.js';
export default {
name: 'Studentenverwaltung',
components: {
CoreSearchbar,
+ NavLanguage,
VerticalSplit,
AppMenu,
+ AppConfig,
StvVerband,
StvList,
StvDetails,
@@ -45,6 +50,8 @@ export default {
permissions: Object,
stvRoot: String,
cisRoot: String,
+ avatarUrl: String,
+ logoutUrl: String,
activeAddons: String, // semicolon separated list of active addons
url_studiensemester_kurzbz: String,
url_mode: String,
@@ -76,15 +83,19 @@ export default {
},
configShowAufnahmegruppen: this.config.showAufnahmegruppen,
configAllowUebernahmePunkte: this.config.allowUebernahmePunkte,
- configUseReihungstestPunkte: this.config.useReihungstestPunkte
+ configUseReihungstestPunkte: this.config.useReihungstestPunkte,
+ appConfig: Vue.computed(() => this.appconfig)
}
},
data() {
return {
+ appconfig: {},
+ configEndpoints: ApiStvConfig,
selected: [],
searchbaroptions: {
origin: 'stv',
calcheightonly: true,
+ nolivesearch: true,
types: {
student: Vue.computed(() => this.$p.t('search/type_student')),
prestudent: Vue.computed(() => this.$p.t('search/type_prestudent'))
@@ -123,6 +134,8 @@ export default {
studiengangKz: undefined,
studiengangKuerzel: '',
studiensemesterKurzbz: this.defaultSemester,
+ selected_semester: undefined,
+ selected_orgform: undefined,
lists: {
nations: [],
sprachen: [],
@@ -131,12 +144,60 @@ export default {
verbandEndpoint: ApiStvVerband
}
},
+ computed: {
+ appMenuExtraItems() {
+ const extraItems = [];
+
+ if (this.studiengangKz !== undefined && this.selected_semester !== undefined) {
+ const studiengang_kz = String(this.studiengangKz);
+ const semester = String(this.selected_semester);
+ const orgform = this.selected_orgform || '';
+
+ extraItems.push({
+ link: FHC_JS_DATA_STORAGE_OBJECT.app_root
+ + 'content/statistik/notenspiegel.php?typ=xls'
+ + '&studiengang_kz=' + studiengang_kz
+ + '&semester=' + semester
+ + '&studiensemester=' + this.studiensemesterKurzbz
+ + '&orgform=' + orgform,
+ description: 'stv/grade_report_xls'
+ });
+ extraItems.push({
+ link: FHC_JS_DATA_STORAGE_OBJECT.app_root
+ + 'content/statistik/notenspiegel_erweitert.php?typ=xls'
+ + '&studiengang_kz=' + studiengang_kz
+ + '&semester=' + semester
+ + '&studiensemester=' + this.studiensemesterKurzbz
+ + '&orgform=' + orgform,
+ description: 'stv/grade_report_xls_extended'
+ });
+ extraItems.push({
+ link: FHC_JS_DATA_STORAGE_OBJECT.app_root
+ + 'content/statistik/notenspiegel.php?typ=html'
+ + '&studiengang_kz=' + studiengang_kz
+ + '&semester=' + semester
+ + '&studiensemester=' + this.studiensemesterKurzbz
+ + '&orgform=' + orgform,
+ description: 'stv/grade_report_html'
+ });
+ }
+
+ return extraItems;
+ }
+ },
watch: {
'url_studiensemester_kurzbz': function (newVal, oldVal) {
if (newVal !== oldVal) {
this.studiensemesterKurzbz = newVal;
- this.$refs.stvList.updateUrl();
- this.$refs.details.reload();
+ if(this.$route.name === 'search')
+ {
+ this.handleSearchUrl();
+ }
+ else
+ {
+ this.$refs.stvList.updateUrl();
+ this.$refs.details.reload();
+ }
}
},
'url_studiengang': function (newVal, oldVal) {
@@ -146,6 +207,25 @@ export default {
},
'url_mode': function () {
this.handlePersonUrl();
+ },
+ url_prestudent_id() {
+ this.handlePersonUrl();
+ },
+ 'appconfig.font_size'() {
+ // add to html class
+ const classList = Object.keys(this.$refs.config.setup.font_size.options);
+ classList.forEach(cn => document.documentElement.classList.remove(cn));
+ document.documentElement.classList.add(this.appconfig.font_size);
+ // recalc Tabulator heights
+ if (this.$el) {
+ const tabulatorEls = this.$el.querySelectorAll('.tabulator');
+ for (const el of tabulatorEls) {
+ const tabulators = Tabulator.findTable(el);
+ if (tabulators) {
+ tabulators[0].searchRows().forEach(row => row.normalizeHeight());
+ }
+ }
+ }
}
},
methods: {
@@ -159,7 +239,7 @@ export default {
}
},
buildPrestudentSearchResultLink(data) {
- return this.$fhcApi.getUri(
+ return this.$api.getUri(
'/studentenverwaltung'
+ '/' + this.studiensemesterKurzbz
+ '/prestudent/'
@@ -167,7 +247,7 @@ export default {
);
},
buildStudentSearchResultLink(data) {
- return this.$fhcApi.getUri(
+ return this.$api.getUri(
'/studentenverwaltung'
+ '/' + this.studiensemesterKurzbz
+ '/student/'
@@ -175,14 +255,14 @@ export default {
);
},
buildPersonSearchResultLink(data) {
- return this.$fhcApi.getUri(
+ return this.$api.getUri(
'/studentenverwaltung'
+ '/' + this.studiensemesterKurzbz
+ '/person/'
+ data.person_id
);
},
- onSelectVerband( {link, studiengang_kz}) {
+ onSelectVerband({ link, studiengang_kz, semester, orgform_kurzbz }) {
let urlpath = String(link);
if (!urlpath.match(/\/prestudent/))
{
@@ -191,6 +271,8 @@ export default {
this.$refs.stvList.updateUrl(ApiStv.students.verband(urlpath));
this.studiengangKz = studiengang_kz;
+ this.selected_semester = semester;
+ this.selected_orgform = orgform_kurzbz;
const stg = this.lists.stgs.find((element) => {
return (element.studiengang_kz === this.studiengangKz);
});
@@ -223,9 +305,6 @@ export default {
studiensemester_kurzbz: v
}
});
-
- this.$refs.stvList.updateUrl();
- this.$refs.details.reload();
},
reloadList() {
this.$refs.stvList.reload();
@@ -249,6 +328,37 @@ export default {
ApiStv.students.person(this.$route.params.person_id, 'CURRENT_SEMESTER'),
true
);
+ } else if (this.$route.params.searchstr) {
+ this.handleSearchUrl();
+ }
+ else
+ {
+ this.clearTabulator();
+ }
+ },
+ handleSearchUrl() {
+ const searchsettings = {
+ searchstr: this.$route.params.searchstr,
+ types: this.$route.params.types?.split('+') || []
+ };
+
+ // init into student list
+ this.$refs.stvList.updateUrl(
+ ApiStv.students.search(searchsettings, this.studiensemesterKurzbz)
+ );
+
+ // init into searchbar
+ this.$refs.searchbar.searchsettings.searchstr = searchsettings.searchstr;
+ this.$refs.searchbar.searchsettings.types = searchsettings.types;
+ this.$nextTick(this.blurSearchbar);
+ },
+ clearTabulator() {
+ if(['index', 'studiensemester'].includes(this.$route.name))
+ {
+ if(this.$refs?.stvList?.$refs?.table?.tabulator)
+ {
+ this.$refs.stvList.$refs.table.tabulator.setData([]);
+ }
}
},
checkUrlStudiengang() {
@@ -269,6 +379,42 @@ export default {
});
}
}
+ else
+ {
+ this.studiengangKz = undefined;
+ this.studiengangKuerzel = '';
+ this.clearTabulator();
+ }
+ },
+ onSearch(e) {
+ const searchsettings = { ...this.$refs.searchbar.searchsettings };
+ if (searchsettings.searchstr.length >= 2) {
+ this.blurSearchbar();
+
+ if (!searchsettings.types.length || searchsettings.types.length == this.$refs.searchbar.types.length) {
+ this.$router.push({
+ name: 'search',
+ params: {
+ studiensemester_kurzbz: this.studiensemesterKurzbz,
+ searchstr: searchsettings.searchstr
+ }
+ });
+ } else {
+ this.$router.push({
+ name: 'search_w_types',
+ params: {
+ studiensemester_kurzbz: this.studiensemesterKurzbz,
+ searchstr: searchsettings.searchstr,
+ types: searchsettings.types.join('+')
+ }
+ });
+ }
+ }
+ },
+ blurSearchbar() {
+ this.$refs.searchbar.$refs.input.blur();
+ this.$refs.searchbar.abort();
+ this.$refs.searchbar.hideresult();
}
},
created() {
@@ -376,10 +522,58 @@ export default {
+
+
+
+
@@ -389,14 +583,38 @@ export default {
@@ -411,5 +629,6 @@ export default {
+
`
};
diff --git a/public/js/components/Stv/Studentenverwaltung/Details.js b/public/js/components/Stv/Studentenverwaltung/Details.js
index 7bd028f3c..dca08c07f 100644
--- a/public/js/components/Stv/Studentenverwaltung/Details.js
+++ b/public/js/components/Stv/Studentenverwaltung/Details.js
@@ -41,25 +41,34 @@ export default {
return Object.fromEntries(Object.entries(this.configStudents).filter(([ , value ]) => !value.showOnlyWithUid && !value.showOnlyWithUid));
}
},
+ watch: {
+ '$p.user_language.value'(n, o) {
+ if (n !== o && o !== undefined)
+ this.loadConfig();
+ }
+ },
methods: {
+ loadConfig() {
+ this.$api
+ .call(ApiStvApp.configStudent())
+ .then(result => {
+ this.configStudent = result.data;
+ })
+ .catch(this.$fhcAlert.handleSystemError);
+ this.$api
+ .call(ApiStvApp.configStudents())
+ .then(result => {
+ this.configStudents = result.data;
+ })
+ .catch(this.$fhcAlert.handleSystemError);
+ },
reload() {
if (this.$refs.tabs?.$refs?.current?.reload)
this.$refs.tabs.$refs.current.reload();
}
},
created() {
- this.$api
- .call(ApiStvApp.configStudent())
- .then(result => {
- this.configStudent = result.data;
- })
- .catch(this.$fhcAlert.handleSystemError);
- this.$api
- .call(ApiStvApp.configStudents())
- .then(result => {
- this.configStudents = result.data;
- })
- .catch(this.$fhcAlert.handleSystemError);
+ this.loadConfig();
},
template: `
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Abschlusspruefung/Abschlusspruefung.js b/public/js/components/Stv/Studentenverwaltung/Details/Abschlusspruefung/Abschlusspruefung.js
index 6e862fc01..6ed710c29 100644
--- a/public/js/components/Stv/Studentenverwaltung/Details/Abschlusspruefung/Abschlusspruefung.js
+++ b/public/js/components/Stv/Studentenverwaltung/Details/Abschlusspruefung/Abschlusspruefung.js
@@ -163,12 +163,12 @@ export default {
frozen: true
},
],
- layout: 'fitDataFill',
+ layout: 'fitDataStretchFrozen',
layoutColumnsOnNewData: false,
height: 'auto',
minHeight: '200',
index: 'abschlusspruefung_id',
- persistenceID: 'stv-details-finalexam'
+ persistenceID: 'stv-details-finalexam-2025112401'
},
tabulatorEvents: [
{
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js b/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js
index 4c29cec3e..a2029b0b9 100644
--- a/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js
+++ b/public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen/Anrechnungen.js
@@ -107,10 +107,10 @@ export default {
frozen: true
},
],
- layout: 'fitDataFill',
+ layout: 'fitDataStretchFrozen',
height: '500',
index: 'anrechnung_id',
- persistenceID: 'stv-details-anrechnungen'
+ persistenceID: 'stv-details-anrechnungen-2025112401'
},
tabulatorEvents: [
{
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js b/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js
index 266c6774e..d03569df4 100644
--- a/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js
+++ b/public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine/Aufnahmetermine.js
@@ -120,12 +120,12 @@ export default {
frozen: true
}
],
- layout: 'fitDataFill',
+ layout: 'fitDataStretchFrozen',
layoutColumnsOnNewData: false,
height: 'auto',
minHeight: 200,
index: 'aufnahmetermin_id',
- persistenceID: 'stv-details-table_admission-dates'
+ persistenceID: 'stv-details-table_admission-dates-2025112401'
},
tabulatorEvents: [
{
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/CombinePeople.js b/public/js/components/Stv/Studentenverwaltung/Details/CombinePeople.js
new file mode 100644
index 000000000..81c1a6860
--- /dev/null
+++ b/public/js/components/Stv/Studentenverwaltung/Details/CombinePeople.js
@@ -0,0 +1,83 @@
+export default {
+ name: "TabCombinePeople",
+ inject: {
+ cisRoot: {
+ from: 'cisRoot'
+ },
+ },
+ props: {
+ modelValue: Object,
+ },
+ data(){
+ return {
+ iframeUrl: null,
+ viewLoaded: false
+ }
+ },
+ computed: {
+ personIds() {
+ return Array.isArray(this.modelValue)
+ ? this.modelValue.map(e => e.person_id)
+ : [this.modelValue.person_id];
+ },
+ detailStringPerson1(){
+ let person1 = this.modelValue[0];
+ return person1.vorname + " " + person1.nachname + "(" + person1.person_id + ")";
+ },
+ detailStringPerson2(){
+ let person2 = this.modelValue[1];
+ return person2.vorname + " " + person2.nachname + "(" + person2.person_id+ ")";
+ },
+
+ },
+ methods: {
+ combinePeople(){
+ this.viewLoaded = true;
+ let person1_id = this.personIds[0];
+ let person2_id = this.personIds[1];
+
+ if(person1_id == person2_id) {
+ return this.$fhcAlert.alertError(this.$p.t('stv', 'error_combinePeople_samePerson'));
+ }
+
+ let linkCombinePeople = this.cisRoot + 'vilesci/stammdaten/personen_wartung.php?person_id_1=' + person1_id + '&person_id_2='+ person2_id;
+ this.openLink(linkCombinePeople);
+ },
+ openLink(url) {
+ this.iframeUrl = url;
+ },
+ goBack(){
+ this.viewLoaded = false;
+ this.iframeUrl = null;
+ }
+ },
+ template: /*html*/ `
+
+
+
+
Personen zusammenlegen
+
+
+
{{$p.t('stv', 'question_combine_people', { person1: detailStringPerson1, person2: detailStringPerson2 })}}
+
+
+
+ ungültige Anzahl: {{this.modelValue.length}}
+
+
+
+
+
+
+
+
+
+
+
+ `
+ };
\ No newline at end of file
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Mobility/List/Purpose.js b/public/js/components/Stv/Studentenverwaltung/Details/Mobility/List/Purpose.js
index 296d29e8d..f877eea78 100644
--- a/public/js/components/Stv/Studentenverwaltung/Details/Mobility/List/Purpose.js
+++ b/public/js/components/Stv/Studentenverwaltung/Details/Mobility/List/Purpose.js
@@ -71,10 +71,10 @@ export default {
frozen: true
},
],
- layout: 'fitColumns',
+ layout: 'fitDataStretchFrozen',
layoutColumnsOnNewData: false,
height: 200,
- persistenceID: 'core-mobility-purpose'
+ persistenceID: 'core-mobility-purpose-2025112401'
},
tabulatorEvents: [
{
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Mobility/List/Support.js b/public/js/components/Stv/Studentenverwaltung/Details/Mobility/List/Support.js
index 3ad523073..d61c60007 100644
--- a/public/js/components/Stv/Studentenverwaltung/Details/Mobility/List/Support.js
+++ b/public/js/components/Stv/Studentenverwaltung/Details/Mobility/List/Support.js
@@ -69,10 +69,10 @@ export default {
frozen: true
},
],
- layout: 'fitColumns',
+ layout: 'fitDataStretchFrozen',
layoutColumnsOnNewData: false,
height: 200,
- persistenceID: 'core-mobility-support'
+ persistenceID: 'core-mobility-support-2025112401'
},
tabulatorEvents: [
{
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Mobility/Mobility.js b/public/js/components/Stv/Studentenverwaltung/Details/Mobility/Mobility.js
index a2b54e7b5..ae7f522b5 100644
--- a/public/js/components/Stv/Studentenverwaltung/Details/Mobility/Mobility.js
+++ b/public/js/components/Stv/Studentenverwaltung/Details/Mobility/Mobility.js
@@ -109,12 +109,12 @@ export default {
frozen: true
},
],
- layout: 'fitDataFill',
+ layout: 'fitDataStretchFrozen',
layoutColumnsOnNewData: false,
height: 'auto',
minHeight: 200,
index: 'bisio_id',
- persistenceID: 'stv-details-table_mobiliy'
+ persistenceID: 'stv-details-table_mobiliy-2025112401'
},
tabulatorEvents: [
{
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis.js b/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis.js
index ce912c240..4d0996b6b 100644
--- a/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis.js
+++ b/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis.js
@@ -217,9 +217,13 @@ export default {
},
columns,
height: '100%',
+ layout: 'fitDataStretchFrozen',
selectable: 1,
selectableRangeMode: 'click',
- persistenceID: 'stv-details-noten-zeugnis'
+ persistenceID: 'stv-details-noten-zeugnis-2025112401',
+ persistence:{
+ columns: ["width", "visible", "frozen"]
+ }
};
}
},
@@ -287,4 +291,4 @@ export default {
`
-};
\ No newline at end of file
+};
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Prestudent/MultiStatus.js b/public/js/components/Stv/Studentenverwaltung/Details/Prestudent/MultiStatus.js
index 9f55d26c2..2828faa59 100644
--- a/public/js/components/Stv/Studentenverwaltung/Details/Prestudent/MultiStatus.js
+++ b/public/js/components/Stv/Studentenverwaltung/Details/Prestudent/MultiStatus.js
@@ -227,15 +227,15 @@ export default{
const rowData = row.getData();
if (this.dataMeldestichtag && this.dataMeldestichtag > rowData.datum)
{
- row.getElement().classList.add('disabled');
+ row.getElement().classList.add('text-black','text-opacity-50','fst-italic');
}
},
- layout: 'fitDataFill',
+ layout: 'fitDataStretchFrozen',
layoutColumnsOnNewData: false,
height: 'auto',
selectable: false,
index: 'statusId',
- persistenceID: 'stv-multistatus'
+ persistenceID: 'stv-multistatus-2025112401'
},
tabulatorEvents: [
{
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js
index a51342c7c..63b80ba37 100644
--- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js
+++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js
@@ -40,6 +40,9 @@ export default {
}
return lehreinheiten;
+ },
+ firmenverwaltungLink(){
+ return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'vilesci/stammdaten/firma_frameset.html';
}
},
props: {
@@ -255,18 +258,25 @@ export default {
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js
index d4f941e4b..084b5daad 100644
--- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js
+++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js
@@ -240,7 +240,7 @@ export default {
frozen: true
},
],
- //layout: 'fitDataFill',
+ layout: 'fitDataStretchFrozen',
height: 'auto',
minHeight: '200',
selectable: 1,
@@ -248,7 +248,7 @@ export default {
persistence:{
columns: true, //persist column layout
},
- persistenceID: 'stv-details-projektarbeit'
+ persistenceID: 'stv-details-projektarbeit-2025112401'
}
return options;
}
@@ -396,8 +396,8 @@ export default {
-
-
+
+
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js
index adcf2f2a8..4bb007b76 100644
--- a/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js
+++ b/public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js
@@ -115,7 +115,7 @@ export default {
frozen: true
},
],
- //layout: 'fitDataFill',
+ layout: 'fitDataStretchFrozen',
layoutColumnsOnNewData: false,
height: 'auto',
minHeight: '100',
@@ -125,7 +125,7 @@ export default {
persistence:{
columns: true, //persist column layout
},
- persistenceID: 'stv-details-projektbetreuer'
+ persistenceID: 'stv-details-projektbetreuer-2025112401'
},
tabulatorEvents: [
{
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Pruefung/Pruefunglist.js b/public/js/components/Stv/Studentenverwaltung/Details/Pruefung/Pruefunglist.js
index 4dd3139ab..62cd47547 100644
--- a/public/js/components/Stv/Studentenverwaltung/Details/Pruefung/Pruefunglist.js
+++ b/public/js/components/Stv/Studentenverwaltung/Details/Pruefung/Pruefunglist.js
@@ -46,8 +46,6 @@ export default{
{title: "Punkte", field: "punkte", visible: false},
{
title: 'Aktionen', field: 'actions',
- minWidth: 150,
- maxWidth: 150,
formatter: (cell, formatterParams, onRendered) => {
let container = document.createElement('div');
container.className = "d-flex gap-2";
@@ -93,7 +91,7 @@ export default{
layoutColumnsOnNewData: false,
height: 'auto',
index: 'pruefung_id',
- persistenceID: 'stv-details-pruefung-list'
+ persistenceID: 'stv-details-pruefung-list-2025112402'
},
tabulatorEvents: [
{
@@ -148,7 +146,6 @@ export default{
listMas: [],
listMarks: [],
zeugnisData: [],
- checkData:[],
filter: false,
statusNew: true,
isStartDropDown: false,
@@ -181,7 +178,7 @@ export default{
this.pruefungData.student_uid = this.uid;
this.pruefungData.note = 9;
- this.pruefungData.datum = new Date();
+ this.pruefungData.datum = luxon.DateTime.now().setZone(FHC_JS_DATA_STORAGE_OBJECT.timezone).toISODate();
this.pruefungData.pruefungstyp_kurzbz = null;
if(lv_id){
this.pruefungData.lehrveranstaltung_id = lv_id;
@@ -193,7 +190,7 @@ export default{
this.isStartDropDown = false;
this.loadPruefung(pruefung_id).then(() => {
this.pruefungData.note = 9;
- this.pruefungData.datum = new Date();
+ this.pruefungData.datum = luxon.DateTime.now().setZone(FHC_JS_DATA_STORAGE_OBJECT.timezone).toISODate();
this.pruefungData.pruefungstyp_kurzbz = null;
this.pruefungData.anmerkung = null;
this.prepareDropdowns();
@@ -229,9 +226,8 @@ export default{
return this.$refs.examData
.call(ApiStvExam.addPruefung(this.pruefungData))
.then(response => {
- this.checkData = response.data;
- if (this.checkData === 2 || this.checkData === 5)
- this.$fhcAlert.alertInfo(this.$p.t('exam', 'hinweis_changeAfterExamDate'));
+ if (response.data)
+ this.$fhcAlert.alertDefault('info', 'Info', response.data, true);
else
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave'));
this.hideModal('pruefungModal');
@@ -243,12 +239,13 @@ export default{
});
},
updatePruefung(pruefung_id){
- this.checkChangeAfterExamDate();
return this.$refs.examData
.call(ApiStvExam.updatePruefung(pruefung_id, this.pruefungData))
.then(response => {
- this.checkData = response.data;
- this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave'));
+ if (response.data)
+ this.$fhcAlert.alertDefault('info', 'Info', response.data, true);
+ else
+ this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave'));
this.hideModal('pruefungModal');
this.resetModal();
}).catch(this.$fhcAlert.handleSystemError)
@@ -266,27 +263,6 @@ export default{
else
this.showHint = false;
},
- checkChangeAfterExamDate() {
- const data = {
- student_uid: this.pruefungData.student_uid,
- studiensemester_kurzbz: this.pruefungData.studiensemester_kurzbz,
- lehrveranstaltung_id: this.pruefungData.lehrveranstaltung_id
- };
- return this.$api
- .call(ApiStvExam.checkZeugnisnoteLv(data))
- .then(result => {
- this.zeugnisData = result.data;
- let checkDate = this.zeugnisData[0].uebernahmedatum === '' ||
- this.zeugnisData[0].benotungsdatum > this.zeugnisData[0].uebernahmedatum
- ? this.zeugnisData[0].benotungsdatum
- : this.zeugnisData[0].uebernahmedatum;
- if (checkDate >= this.pruefungData.datum
- && this.pruefungData.note !== this.zeugnisData[0].note) {
- this.$fhcAlert.alertInfo(this.$p.t('exam', 'hinweis_changeAfterExamDate'));
- }
- })
- .catch(this.$fhcAlert.handleSystemError);
- },
deletePruefung(pruefung_id) {
return this.$api
.call(ApiStvExam.deletePruefung(pruefung_id))
@@ -534,6 +510,7 @@ export default{
container-class="mb-3"
type="DatePicker"
v-model="pruefungData.datum"
+ model-type="yyyy-MM-dd"
name="datum"
:label="$p.t('global/datum')"
auto-apply
diff --git a/public/js/components/Stv/Studentenverwaltung/List.js b/public/js/components/Stv/Studentenverwaltung/List.js
index 2614ebc1f..953462a74 100644
--- a/public/js/components/Stv/Studentenverwaltung/List.js
+++ b/public/js/components/Stv/Studentenverwaltung/List.js
@@ -2,6 +2,8 @@ import {CoreFilterCmpt} from "../../filter/Filter.js";
import ListNew from './List/New.js';
import ListFilter from './List/Filter.js';
+import { capitalize } from '../../../helpers/StringHelpers.js';
+
import draggable from '../../../directives/draggable.js';
export default {
@@ -133,7 +135,17 @@ export default {
{
return Promise.resolve({ data: []});
}
- return this.$api.call({method: 'post', url, params});
+ /**
+ * NOTE(chris): Because of a bug in Tabulator
+ * we need to get the params from elsewhere.
+ * @see https://github.com/olifolkerd/tabulator/issues/4318
+ */
+ const apiconfig = {
+ ...this.tabulatorOptions.ajaxConfig,
+ url: this.tabulatorOptions.ajaxURL,
+ params: this.tabulatorOptions.ajaxParams
+ };
+ return this.$api.call(apiconfig);
},
ajaxResponse: (url, params, response) => {
return response?.data;
@@ -175,7 +187,7 @@ export default {
count: 0,
filteredcount: 0,
selectedcount: 0,
- currentEndpointRawUrl: ''
+ currentEndpoint: null
}
},
computed: {
@@ -228,7 +240,84 @@ export default {
return "StudentList_" + today + ".csv";
}
},
+ watch: {
+ '$p.user_language.value'(n, o) {
+ if (n !== o && o !== undefined && this.$refs.table.tableBuilt) {
+ this.translateTabulator();
+ }
+ }
+ },
methods: {
+ translateTabulator() {
+ this.$p
+ .loadCategory(['global', 'person', 'lehre', 'ui', 'profilUpdate', 'admission', 'stv'])
+ .then(() => {
+ const translations = {
+ uid: capitalize(this.$p.t('person/uid')),
+ titelpre: capitalize(this.$p.t('person/titelpre')),
+ nachname: capitalize(this.$p.t('person/nachname')),
+ vorname: capitalize(this.$p.t('person/vorname')),
+ wahlname: capitalize(this.$p.t('person/wahlname')),
+ vornamen: capitalize(this.$p.t('person/vornamen')),
+ titelpost: capitalize(this.$p.t('person/titelpost')),
+ ersatzkennzeichen: capitalize(this.$p.t('person/ersatzkennzeichen')),
+ gebdatum: capitalize(this.$p.t('person/geburtsdatum')),
+ geschlecht: capitalize(this.$p.t('person/geschlecht')),
+ semester: capitalize(this.$p.t('lehre/sem')),
+ verband: capitalize(this.$p.t('lehre/verb')),
+ gruppe: capitalize(this.$p.t('lehre/grp')),
+ studiengang: capitalize(this.$p.t('lehre/studiengang')),
+ studiengang_kz: capitalize(this.$p.t('lehre/studiengang_kz')),
+ matrikelnr: capitalize(this.$p.t('person/personenkennzeichen')),
+ person_id: capitalize(this.$p.t('person/person_id')),
+ status: capitalize(this.$p.t('global/status')),
+ status_datum: capitalize(this.$p.t('profilUpdate/statusDate')),
+ status_bestaetigung: capitalize(this.$p.t('global/status_bestaetigung')),
+ mail_privat: capitalize(this.$p.t('person/email_private')),
+ mail_intern: capitalize(this.$p.t('person/email_intern')),
+ anmerkungen: capitalize(this.$p.t('stv/notes_person')),
+ anmerkung: capitalize(this.$p.t('stv/notes_prestudent')),
+ orgform_kurzbz: capitalize(this.$p.t('lehre/orgform')),
+ aufmerksamdurch_kurzbz: capitalize(this.$p.t('person/aufmerksamDurch')),
+ punkte: capitalize(this.$p.t('admission/gesamtpunkte')),
+ aufnahmegruppe_kurzbz: capitalize(this.$p.t('stv/aufnahmegruppe_kurzbz')),
+ dual: capitalize(this.$p.t('lehre/dual_short')),
+ matr_nr: capitalize(this.$p.t('person/matrikelnummer')),
+ studienplan_bezeichnung: capitalize(this.$p.t('lehre/studienplan')),
+ prestudent_id: capitalize(this.$p.t('ui/prestudent_id')),
+ priorisierung_relativ: capitalize(this.$p.t('lehre/prioritaet')),
+ mentor: capitalize(this.$p.t('stv/mentor')),
+ bnaktiv: capitalize(this.$p.t('person/aktiv'))
+ };
+
+ /** NOTE(chris):
+ * use this approach because updateDefinition
+ * on the Tabulator columns is way slower and
+ * freezes up the GUI.
+ */
+ // Overwrite definition for column show/hide
+ this.$refs.table.tabulator.getColumns().forEach(col => {
+ const trans = translations[col.getField()];
+ if (!trans)
+ return;
+ col.getDefinition().title = trans;
+ });
+ // Overwrite node in dom
+ this.$refs.table.tabulator.element
+ .querySelectorAll('.tabulator-col[tabulator-field]')
+ .forEach(el => {
+ const field = el.getAttribute('tabulator-field');
+ if (!translations[field])
+ return;
+
+ const title = el.querySelector('.tabulator-col-title');
+ if (!title)
+ return;
+
+ title.innerText = translations[field];
+ });
+ });
+ },
reload() {
this.$refs.table.reloadTable();
},
@@ -273,16 +362,20 @@ export default {
updateUrl(endpoint, first) {
this.lastSelected = first ? undefined : this.selected;
- if( endpoint === undefined )
+ console.log('function param endpoint: ' + JSON.stringify(endpoint));
+ console.log('current endpoint: ' + JSON.stringify(this.currentEndpoint));
+
+ if( endpoint === undefined && this.currentEndpoint === null)
{
- endpoint = {url: this.currentEndpointRawUrl};
- }
- else if( endpoint.url === undefined )
+ endpoint = { url: '' };
+ }
+ else if( endpoint === undefined )
{
- endpoint.url = this.currentEndpointRawUrl;
- } else
+ endpoint = JSON.parse(JSON.stringify(this.currentEndpoint));
+ }
+ else
{
- this.currentEndpointRawUrl = endpoint.url;
+ this.currentEndpoint = JSON.parse(JSON.stringify(endpoint));
}
endpoint.url = endpoint.url.replace(
@@ -290,20 +383,25 @@ export default {
encodeURIComponent(this.currentSemester)
);
- const params = {};
- if (this.filter.length)
+ const params = (endpoint?.params !== undefined) ? endpoint.params : {};
+ let method = (endpoint?.method !== undefined) ? endpoint.method : 'get';
+ if (this.filter.length && !endpoint.url.match(/\/search\//))
+ {
params.filter = this.filter;
+ method = 'post';
+ }
+ this.tabulatorOptions.ajaxURL = endpoint.url;
+ this.tabulatorOptions.ajaxParams = { ...params };
+ this.tabulatorOptions.ajaxConfig = {method};
if (!this.$refs.table.tableBuilt) {
- if (!this.$refs.table.tabulator) {
- this.tabulatorOptions.ajaxURL = endpoint.url;
- this.tabulatorOptions.ajaxParams = params;
- } else
+ if (this.$refs.table.tabulator) {
this.$refs.table.tabulator.on("tableBuilt", () => {
- this.$refs.table.tabulator.setData(endpoint.url, params);
+ this.$refs.table.tabulator.setData(endpoint.url, params, method);
});
+ }
} else
- this.$refs.table.tabulator.setData(endpoint.url, params);
+ this.$refs.table.tabulator.setData(endpoint.url, params, method);
},
dragCleanup(evt) {
if (evt.dataTransfer.dropEffect == 'none')
@@ -402,6 +500,7 @@ export default {
*/`
:new-btn-label="$p.t('stv/action_new')"
@click:new="actionNewPrestudent"
+ @table-built="translateTabulator"
>
diff --git a/public/js/components/Stv/Studentenverwaltung/Verband.js b/public/js/components/Stv/Studentenverwaltung/Verband.js
index 86e01a55b..1ff9d2ed9 100644
--- a/public/js/components/Stv/Studentenverwaltung/Verband.js
+++ b/public/js/components/Stv/Studentenverwaltung/Verband.js
@@ -16,11 +16,17 @@ export default {
inject: {
$reloadList: {
from: '$reloadList',
- required: true
+ default: () => {}
},
currentSemester: {
from: 'currentSemester',
required: true
+ },
+ appConfig: {
+ from: 'appConfig',
+ default: {
+ number_displayed_past_studiensemester: 5
+ }
}
},
emits: [
@@ -52,6 +58,9 @@ export default {
return this.nodes.filter(node => this.favorites.list.includes(node.key));
return this.nodes;
+ },
+ noSemReloadNodes() {
+ return this.nodes.reduce(this.mapNodesToNoSemReloadNodes, []);
}
},
watch: {
@@ -59,6 +68,14 @@ export default {
if (newVal !== oldVal) {
this.setPreselection();
}
+ },
+ 'appConfig.number_displayed_past_studiensemester'(newVal, oldVal) {
+ if (oldVal !== undefined) {
+ this.noSemReloadNodes.forEach(node => {
+ delete node.children;
+ this.onExpandTreeNode(node);
+ });
+ }
}
},
methods: {
@@ -114,7 +131,14 @@ export default {
},
onSelectTreeNode(node) {
if (node.data.link)
- this.$emit('selectVerband', {link: node.data.link, studiengang_kz: node.data.stg_kz});
+ this.$emit('selectVerband', {link: node.data.link, studiengang_kz: node.data.stg_kz, semester: node.data.semester, orgform_kurzbz: node.data.orgform_kurzbz});
+ },
+ mapNodesToNoSemReloadNodes(result, node) {
+ if (node.data.no_sem_reload)
+ result.push(node);
+ if (node.children)
+ result = node.children.reduce(this.mapNodesToNoSemReloadNodes, result);
+ return result;
},
mapResultToTreeData(el) {
const cp = {
@@ -187,22 +211,25 @@ export default {
if (!currentNode)
return;
- const currentSelectedKey = Object.keys(this.selectedKey).find(Boolean);
- if (currentSelectedKey) {
- if (currentSelectedKey == currentKey)
- return;
- /**
- * Do not select a new entry if the current is a child of the new one.
- * This happens if a child entry of a new stg is selected and the router
- * tries to select the stg root entry (because subtrees do not have
- * routes yet)
- */
- const isChild = this.findNodeByKey(
- currentSelectedKey,
- currentNode.children
- );
- if (isChild)
- return;
+ if(this.selectedKey)
+ {
+ const currentSelectedKey = Object.keys(this.selectedKey).find(Boolean);
+ if (currentSelectedKey) {
+ if (currentSelectedKey == currentKey)
+ return;
+ /**
+ * Do not select a new entry if the current is a child of the new one.
+ * This happens if a child entry of a new stg is selected and the router
+ * tries to select the stg root entry (because subtrees do not have
+ * routes yet)
+ */
+ const isChild = this.findNodeByKey(
+ currentSelectedKey,
+ currentNode.children || []
+ );
+ if (isChild)
+ return;
+ }
}
for (let i = 1; i < parts.length; i++)
diff --git a/public/js/components/Tabs.js b/public/js/components/Tabs.js
index 0b9b82027..56506bd9d 100644
--- a/public/js/components/Tabs.js
+++ b/public/js/components/Tabs.js
@@ -33,7 +33,8 @@ export default {
data() {
return {
current: null,
- tabs: {}
+ tabs: {},
+ count: null
}
},
computed: {
@@ -113,10 +114,12 @@ export default {
};
}
- if (Array.isArray(config))
+ if (Array.isArray(config)) {
config.forEach((item, key) => _addToTabs(key, item));
- else
+ }
+ else {
Object.entries(config).forEach(([key, item]) => _addToTabs(key, item));
+ }
if (this.current === null || !tabs[this.current]) {
if (tabs[this.default])
@@ -129,6 +132,57 @@ export default {
updateSuffix() {
this.getTabSuffix(this.currentTab);
},
+ removeInvalidCountTabs(){
+ if(this.modelValue.length)
+ {
+ let countIst = this.modelValue.length;
+ const tabsToDelete = [];
+
+ Object.entries(this.config).forEach(([key, item]) => {
+
+ const target = item?.config ? item : item?.value || item;
+
+ // check config for validCountMulti
+ if (target.config?.validCountMulti !== undefined) {
+ let tab;
+ let countSoll;
+ tab = key;
+ countSoll = target.config.validCountMulti;
+
+ //check if tab is existing
+ if (countSoll !== undefined && countSoll == countIst) {
+ //add tab if it was removed before
+ if (tab in this.tabs == false) {
+ const value = Vue.reactive({
+ suffix: '',
+ showSuffix: item.showSuffix || false
+ });
+
+ this.tabs[tab] = {
+ component: Vue.markRaw(Vue.defineAsyncComponent(() => import(item.component))),
+ title: Vue.computed(() => item.title || tab),
+ config: item.config,
+ tab,
+ value,
+ suffixhelper: item.suffixhelper ?? null
+ };
+ }
+ }
+
+ //add to toDeleteArray if count is not allowed
+ if (countSoll !== undefined && countSoll !== countIst) {
+ tabsToDelete.push(tab);
+ }
+ }
+ });
+
+ // Delete all tabs with count not allowed
+ tabsToDelete.forEach(k => {
+ delete this.tabs[k];
+ });
+
+ }
+ },
async getTabSuffix(tab) {
if (!tab.value.showSuffix) {
return;
@@ -151,9 +205,11 @@ export default {
},
mounted() {
this.getTabSuffixes();
+ this.removeInvalidCountTabs();
},
updated() {
this.getTabSuffixes();
+ this.removeInvalidCountTabs();
},
template: `
diff --git a/public/js/components/navigation/Language.js b/public/js/components/navigation/Language.js
new file mode 100644
index 000000000..4d26dadc0
--- /dev/null
+++ b/public/js/components/navigation/Language.js
@@ -0,0 +1,62 @@
+/**
+ * Copyright (C) 2025 fhcomplete.org
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+export default {
+ emits: [
+ 'changed'
+ ],
+ props: {
+ activeClass: {
+ type: String,
+ default: 'active'
+ },
+ itemClass: {
+ type: [String, Array, Object],
+ default: ''
+ }
+ },
+ data() {
+ return {
+ languages: FHC_JS_DATA_STORAGE_OBJECT.server_languages
+ };
+ },
+ methods:{
+ onChange(lang) {
+ if (this.languages.some(l => l.sprache === lang)) {
+ this.$p
+ .setLanguage(lang)
+ .then(() => {
+ if (document.querySelector('[cis4Reload]'))
+ window.location.reload();
+ else
+ this.$emit('changed', lang);
+ });
+ }
+ }
+ },
+ template: /*html*/`
+
+
+
`
+};
\ No newline at end of file
diff --git a/public/js/components/searchbar/searchbar.js b/public/js/components/searchbar/searchbar.js
index 56fba15c6..d6c93198e 100644
--- a/public/js/components/searchbar/searchbar.js
+++ b/public/js/components/searchbar/searchbar.js
@@ -23,7 +23,17 @@ export default {
mergedStudent,
mergedPerson
},
- props: [ "searchoptions", "searchfunction" ],
+ props: {
+ searchoptions: {
+ type: Object,
+ required: true
+ },
+ searchfunction: {
+ type: Function,
+ required: true
+ },
+ showBtnSubmit: Boolean
+ },
provide() {
return {
query: Vue.computed(() => this.lastQuery)
@@ -102,11 +112,22 @@ export default {
>
+