Merge branch 'master' into epic-56039/LV-Evaluierung

This commit is contained in:
Cristina
2025-12-09 17:06:06 +01:00
59 changed files with 2320 additions and 394 deletions
+6 -1
View File
@@ -61,7 +61,11 @@ $config['tabs'] =
'notes' => [ 'notes' => [
//if true, the count of Messages will be shown in the header of the Tab Messages //if true, the count of Messages will be shown in the header of the Tab Messages
'showCountNotes' => true '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 // List of fields to show when ZGV_DOKTOR_ANZEIGEN is defined
@@ -117,5 +121,6 @@ $config['students_tab_order'] = [
'status', 'status',
'groups', 'groups',
'finalexam', 'finalexam',
'combinePeople',
'archive', 'archive',
]; ];
+1 -1
View File
@@ -14,7 +14,7 @@ class Pub extends Auth_Controller
{ {
parent::__construct( parent::__construct(
array( array(
'bild' => ['basis/cis:r'] 'bild' => ['basis/cis:r', 'assistenz:r']
) )
); );
} }
@@ -298,7 +298,7 @@ class Aufnahmetermine extends FHCAPI_Controller
$reihungstestangetreten = $reihungstestangetreten =
(isset($formData['reihungstestangetreten']) && !empty($formData['reihungstestangetreten'])) (isset($formData['reihungstestangetreten']) && !empty($formData['reihungstestangetreten']))
? $formData['reihungstestangetreten'] ? $formData['reihungstestangetreten']
: null; : false;
$aufnahmegruppe_kurzbz = $aufnahmegruppe_kurzbz =
(isset($formData['aufnahmegruppe_kurzbz']) && !empty($formData['aufnahmegruppe_kurzbz'])) (isset($formData['aufnahmegruppe_kurzbz']) && !empty($formData['aufnahmegruppe_kurzbz']))
? $formData['aufnahmegruppe_kurzbz'] ? $formData['aufnahmegruppe_kurzbz']
@@ -33,6 +33,8 @@ class Config extends FHCAPI_Controller
{ {
// TODO(chris): permissions // TODO(chris): permissions
parent::__construct([ parent::__construct([
'get' => ['admin:r', 'assistenz:r'],
'set' => ['admin:r', 'assistenz:r'],
'filter' => ['admin:r', 'assistenz:r'], 'filter' => ['admin:r', 'assistenz:r'],
'student' => ['admin:r', 'assistenz:r'], 'student' => ['admin:r', 'assistenz:r'],
'students' => ['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 * Get the config for the student filters
* *
* @return void * @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'] = [ $result['kontaktieren'] = [
'title' => $this->p->t('stv', 'tab_kontaktieren'), 'title' => $this->p->t('stv', 'tab_kontaktieren'),
'component' => absoluteJsImportUrl('public/js/components/Stv/Studentenverwaltung/Details/Kontaktieren.js'), 'component' => absoluteJsImportUrl('public/js/components/Stv/Studentenverwaltung/Details/Kontaktieren.js'),
@@ -83,7 +83,7 @@ class GemeinsameStudien extends FHCAPI_Controller
{ {
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$this->StudiensemesterModel->addOrder('studienjahr_kurzbz', 'DESC'); $this->StudiensemesterModel->addOrder('start', 'DESC');
$result = $this->StudiensemesterModel->load(); $result = $this->StudiensemesterModel->load();
$data = $this->getDataOrTerminateWithError($result); $data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data); $this->terminateWithSuccess($data);
@@ -147,7 +147,8 @@ class Gruppen extends FHCAPI_Controller
'lehre' => true, 'lehre' => true,
'sichtbar' => true, 'sichtbar' => true,
'aktiv' => true, 'aktiv' => true,
'direktinskription' => false 'direktinskription' => false,
'generiert' => false
]); ]);
$data = $this->getDataOrTerminateWithError($result); $data = $this->getDataOrTerminateWithError($result);
@@ -268,10 +268,6 @@ class Projektarbeit extends FHCAPI_Controller
{ {
$this->form_validation->set_data($formData); $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', [ $this->form_validation->set_rules('projekttyp_kurzbz', 'Projekttyp', 'required', [
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Projekttyp']) 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Projekttyp'])
]); ]);
@@ -18,6 +18,8 @@
if (! defined('BASEPATH')) exit('No direct script access allowed'); 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 * This controller operates between (interface) the JS (GUI) and the back-end
* Provides data to the ajax get calls about addresses * Provides data to the ajax get calls about addresses
@@ -111,7 +113,7 @@ class Pruefung extends FHCAPI_Controller
// Load language phrases // Load language phrases
$this->loadPhrases([ $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 * @param lehrveranstaltung_id, student_uid, lehreinheit_id
* *
* @return values on success * @return void
* 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)
*/ */
public function insertPruefung() public function insertPruefung()
{ {
$authUID = getAuthUID(); $this->insertOrUpdatePruefung();
$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);
} }
/** /**
@@ -348,8 +187,6 @@ class Pruefung extends FHCAPI_Controller
* @param pruefung_id * @param pruefung_id
* *
* @return success or error * @return success or error
*
* no impact on lehre.tbl_zeugnisnote
*/ */
public function updatePruefung($pruefung_id) public function updatePruefung($pruefung_id)
{ {
@@ -359,48 +196,7 @@ class Pruefung extends FHCAPI_Controller
if (!$oldpruefung) if (!$oldpruefung)
show_404(); // Pruefung that should be updated does not exist show_404(); // Pruefung that should be updated does not exist
$authUID = getAuthUID(); $this->insertOrUpdatePruefung($pruefung_id);
$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);
} }
/** /**
@@ -574,4 +370,198 @@ class Pruefung extends FHCAPI_Controller
return $this->terminateWithSuccess($data); 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();
}
} }
@@ -765,6 +765,86 @@ class Students extends FHCAPI_Controller
$this->terminateWithSuccess($data); $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|null $studiensemester_kurzbz
* @param string $type * @param string $type
@@ -165,7 +165,17 @@ class Verband extends FHCAPI_Controller
$this->StudiengangModel->addDistinct(); $this->StudiengangModel->addDistinct();
$this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", semester) AS link", false); $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('semester');
$this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false); $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'); $this->StudiengangModel->addOrder('semester');
if ($org_form !== null) { if ($org_form !== null) {
$this->StudiengangModel->addSelect("v.orgform_kurzbz");
$this->StudiengangModel->db->group_start(); $this->StudiengangModel->db->group_start();
$this->StudiengangModel->db->where('v.semester', 0); $this->StudiengangModel->db->where('v.semester', 0);
$this->StudiengangModel->db->or_where('v.orgform_kurzbz', $org_form); $this->StudiengangModel->db->or_where('v.orgform_kurzbz', $org_form);
@@ -188,6 +199,7 @@ class Verband extends FHCAPI_Controller
array_unshift($list, [ array_unshift($list, [
'name' => 'PreStudent', 'name' => 'PreStudent',
'link' => $link . 'prestudent', 'link' => $link . 'prestudent',
'no_sem_reload' => true,
'stg_kz' => (int)$studiengang_kz, 'stg_kz' => (int)$studiengang_kz,
'children' => $this->getStdSem($link . 'prestudent/', $studiengang_kz) 'children' => $this->getStdSem($link . 'prestudent/', $studiengang_kz)
]); ]);
@@ -216,7 +228,6 @@ class Verband extends FHCAPI_Controller
$list = array_merge($list, $result); $list = array_merge($list, $result);
} }
} }
} }
$this->terminateWithSuccess($list); $this->terminateWithSuccess($list);
} }
@@ -233,10 +233,10 @@ class Person extends API_Controller
//Quersumme bilden //Quersumme bilden
for ($i = 0; $i < 10; $i++) 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'); return error('SVNR ist ungueltig');
} }
@@ -244,7 +244,7 @@ class Person extends API_Controller
if (mb_strlen($person['svnr']) == 12) if (mb_strlen($person['svnr']) == 12)
{ {
$last = substr($person['svnr'], 10, 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'); return error('SVNR ist ungueltig');
} }
@@ -22,6 +22,7 @@ class InfoCenter extends Auth_Controller
const REIHUNGSTESTABSOLVIERT_PAGE = 'reihungstestAbsolviert'; const REIHUNGSTESTABSOLVIERT_PAGE = 'reihungstestAbsolviert';
const ABGEWIESEN_PAGE = 'abgewiesen'; const ABGEWIESEN_PAGE = 'abgewiesen';
const AUFGENOMMEN_PAGE = 'aufgenommen'; const AUFGENOMMEN_PAGE = 'aufgenommen';
const ONBOARDING_PAGE = 'onboarding';
const SHOW_DETAILS_PAGE = 'showDetails'; const SHOW_DETAILS_PAGE = 'showDetails';
const SHOW_ZGV_DETAILS_PAGE = 'showZGVDetails'; const SHOW_ZGV_DETAILS_PAGE = 'showZGVDetails';
const ZGV_UBERPRUEFUNG_PAGE = 'ZGVUeberpruefung'; const ZGV_UBERPRUEFUNG_PAGE = 'ZGVUeberpruefung';
@@ -116,6 +117,7 @@ class InfoCenter extends Auth_Controller
'index' => 'infocenter:r', 'index' => 'infocenter:r',
'freigegeben' => 'infocenter:r', 'freigegeben' => 'infocenter:r',
'abgewiesen' => 'infocenter:r', 'abgewiesen' => 'infocenter:r',
'onboarding' => 'infocenter:r',
'aufgenommen' => 'infocenter:r', 'aufgenommen' => 'infocenter:r',
'reihungstestAbsolviert' => 'infocenter:r', 'reihungstestAbsolviert' => 'infocenter:r',
'showDetails' => 'infocenter:r', 'showDetails' => 'infocenter:r',
@@ -230,6 +232,13 @@ class InfoCenter extends Auth_Controller
$this->load->view('system/infocenter/infocenterAbgewiesen.php'); $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 * Aufgenommene page of the InfoCenter tool
@@ -1553,6 +1562,7 @@ class InfoCenter extends Auth_Controller
$reihungstestAbsolviertLink = site_url(self::INFOCENTER_URI.'/'.self::REIHUNGSTESTABSOLVIERT_PAGE); $reihungstestAbsolviertLink = site_url(self::INFOCENTER_URI.'/'.self::REIHUNGSTESTABSOLVIERT_PAGE);
$abgewiesenLink = site_url(self::INFOCENTER_URI.'/'.self::ABGEWIESEN_PAGE); $abgewiesenLink = site_url(self::INFOCENTER_URI.'/'.self::ABGEWIESEN_PAGE);
$aufgenommenLink = site_url(self::INFOCENTER_URI.'/'.self::AUFGENOMMEN_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); $currentFilterId = $this->input->get(self::FILTER_ID);
if (isset($currentFilterId)) if (isset($currentFilterId))
@@ -1561,6 +1571,7 @@ class InfoCenter extends Auth_Controller
$reihungstestAbsolviertLink .= '?'.self::PREV_FILTER_ID.'='.$currentFilterId; $reihungstestAbsolviertLink .= '?'.self::PREV_FILTER_ID.'='.$currentFilterId;
$abgewiesenLink .= '?'.self::PREV_FILTER_ID.'='.$currentFilterId; $abgewiesenLink .= '?'.self::PREV_FILTER_ID.'='.$currentFilterId;
$aufgenommenLink .= '?'.self::PREV_FILTER_ID.'='.$currentFilterId; $aufgenommenLink .= '?'.self::PREV_FILTER_ID.'='.$currentFilterId;
$onboardingLink .= '?'.self::PREV_FILTER_ID.'='.$currentFilterId;
} }
$this->navigationlib->setSessionMenu( $this->navigationlib->setSessionMenu(
@@ -1624,6 +1635,18 @@ class InfoCenter extends Auth_Controller
'', // target '', // target
40 // sort 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); $link = site_url(self::ZGV_UEBERPRUEFUNG_URI);
if ($origin_page === self::ABGEWIESEN_PAGE) if ($origin_page === self::ABGEWIESEN_PAGE)
$link = site_url(self::INFOCENTER_URI.'/'.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) if ($origin_page === self::AUFGENOMMEN_PAGE)
$link = site_url(self::INFOCENTER_URI.'/'.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); $freigegebenLink = site_url(self::INFOCENTER_URI.'/'.self::FREIGEGEBEN_PAGE);
$absolviertLink = site_url(self::INFOCENTER_URI.'/'.self::REIHUNGSTESTABSOLVIERT_PAGE); $absolviertLink = site_url(self::INFOCENTER_URI.'/'.self::REIHUNGSTESTABSOLVIERT_PAGE);
$abgewiesenLink = site_url(self::INFOCENTER_URI.'/'.self::ABGEWIESEN_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); $prevFilterId = $this->input->get(self::PREV_FILTER_ID);
if (isset($prevFilterId)) 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
)
);
}
} }
/** /**
+4 -1
View File
@@ -22,7 +22,8 @@
'public/css/components/function.css' 'public/css/components/function.css'
], ],
'customJSs' => [ '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/tree/tree.min.js',
#'vendor/npm-asset/primevue/toast/toast.min.js' #'vendor/npm-asset/primevue/toast/toast.min.js'
], ],
@@ -53,6 +54,8 @@ $configArray = [
active-addons="<?= defined('ACTIVE_ADDONS') ? ACTIVE_ADDONS : ''; ?>" active-addons="<?= defined('ACTIVE_ADDONS') ? ACTIVE_ADDONS : ''; ?>"
stv-root="<?= site_url('Studentenverwaltung'); ?>" stv-root="<?= site_url('Studentenverwaltung'); ?>"
cis-root="<?= CIS_ROOT; ?>" 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)); ?>" :permissions="<?= htmlspecialchars(json_encode($permissions)); ?>"
:config="<?= htmlspecialchars(json_encode($configArray)); ?>" :config="<?= htmlspecialchars(json_encode($configArray)); ?>"
> >
@@ -0,0 +1,47 @@
<?php
$this->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')
)
);
?>
<div id="wrapper">
<?php echo $this->widgetlib->widget('NavigationWidget'); ?>
<div id="page-wrapper">
<div class="container-fluid">
<div class="row">
<div class="col-lg-12">
<h3 class="page-header">
Electronic Onboarding
</h3>
</div>
</div>
<div>
<?php $this->load->view('system/infocenter/onboardingData.php'); ?>
</div>
</div>
</div>
</div>
<?php $this->load->view('templates/FHC-Footer'); ?>
@@ -0,0 +1,116 @@
<?php
$APP = '\'infocenter\'';
$KENNZEICHEN = '\'eobRegistrierungsId\'';
$query = '
SELECT
p.person_id AS "PersonId",
p.vorname AS "Vorname",
p.nachname AS "Nachname",
pl.zeitpunkt AS "LockDate",
pl.lockuser AS "LockUser",
rueck.datum_bis AS "HoldDate",
rueck.bezeichnung AS "Rueckstellgrund"
FROM public.tbl_person p
JOIN tbl_kennzeichen ON p.person_id = tbl_kennzeichen.person_id AND kennzeichentyp_kurzbz = '. $KENNZEICHEN .'
LEFT JOIN (
SELECT tpl.person_id,
tpl.zeitpunkt,
sp.nachname AS lockuser
FROM system.tbl_person_lock tpl
JOIN public.tbl_benutzer sb USING (uid)
JOIN public.tbl_person sp ON sb.person_id = sp.person_id
WHERE tpl.app = '.$APP.'
) pl ON p.person_id = pl.person_id
LEFT JOIN (
SELECT
tbl_rueckstellung.person_id,
tbl_rueckstellung.datum_bis,
tbl_rueckstellung.status_kurzbz,
array_to_json(bezeichnung_mehrsprachig::varchar[])->>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(
'<a href="%s?person_id=%s&origin_page=%s&fhc_controller_id=%s&prev_filter_id=%s">Details</a>',
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);
?>
+5
View File
@@ -62,6 +62,11 @@ if(!$rechte->isBerechtigt('student/noten',$studiengang_kz, 's'))
$semester = isset($_GET['semester'])?$_GET['semester']:''; $semester = isset($_GET['semester'])?$_GET['semester']:'';
$typ = isset($_GET['typ'])?$_GET['typ']:''; $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=='') if($semester=='')
die('Bitte ein Semester auswaehlen'); die('Bitte ein Semester auswaehlen');
@@ -64,6 +64,11 @@ if (!$rechte->isBerechtigt('student/noten', $studiengang_kz, 's'))
$semester = isset($_GET['semester']) ? $_GET['semester'] : ''; $semester = isset($_GET['semester']) ? $_GET['semester'] : '';
$typ = isset($_GET['typ']) ? $_GET['typ'] : ''; $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 == '') if ($semester == '')
die('Bitte ein Semester auswaehlen'); die('Bitte ein Semester auswaehlen');
+6 -6
View File
@@ -178,7 +178,7 @@ class File_CSV
return $field; 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 substr($field, 1, -1);
} }
return $field; return $field;
@@ -230,7 +230,7 @@ class File_CSV
} elseif ($c == "\n" || $c == "\r") { } elseif ($c == "\n" || $c == "\r") {
$sub = ($prev == "\r") ? 2 : 1; $sub = ($prev == "\r") ? 2 : 1;
if ((strlen($buff) >= $sub) && if ((strlen($buff) >= $sub) &&
($buff{strlen($buff) - $sub} == $quote)) ($buff[strlen($buff) - $sub] == $quote))
{ {
$in_quote = false; $in_quote = false;
} }
@@ -312,9 +312,9 @@ class File_CSV
$last =& $fields[count($fields) - 1]; $last =& $fields[count($fields) - 1];
// Fallback to read the line with readQuoted when guess // Fallback to read the line with readQuoted when guess
// that the simple explode won't work right // that the simple explode won't work right
if (($last{strlen($last) - 1} == "\n" if (($last[strlen($last) - 1] == "\n"
&& $last{0} == $conf['quote'] && $last[0] == $conf['quote']
&& $last{strlen(rtrim($last)) - 1} != $conf['quote']) && $last[strlen(rtrim($last)) - 1] != $conf['quote'])
|| ||
(count($fields) != $conf['fields']) (count($fields) != $conf['fields'])
// XXX perhaps there is a separator inside a quoted field // XXX perhaps there is a separator inside a quoted field
@@ -511,4 +511,4 @@ class File_CSV
return true; return true;
} }
} }
?> ?>
+5 -5
View File
@@ -96,7 +96,7 @@ class File_Util
{ {
if (File_Util::isAbsolute($path)) { if (File_Util::isAbsolute($path)) {
if (FILE_WIN32) { if (FILE_WIN32) {
return substr($path, $path{3} == '\\' ? 4 : 3); return substr($path, $path[3] == '\\' ? 4 : 3);
} }
return ltrim($path, '/'); return ltrim($path, '/');
} }
@@ -182,7 +182,7 @@ class File_Util
if (FILE_WIN32) { if (FILE_WIN32) {
return preg_match('/^[a-zA-Z]:(\\\|\/)/', $path); 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 { } else {
$cwd = getcwd(); $cwd = getcwd();
$drive = substr($cwd, 0, 2); $drive = substr($cwd, 0, 2);
if ($path{0} !== $separator{0}) { if ($path[0] !== $separator[0]) {
$path = substr($cwd, 3) . $separator . $path; $path = substr($cwd, 3) . $separator . $path;
} }
} }
} elseif ($path{0} !== $separator) { } elseif ($path[0] !== $separator) {
$path = getcwd() . $separator . $path; $path = getcwd() . $separator . $path;
} }
@@ -323,7 +323,7 @@ class File_Util
$entries = array(); $entries = array();
for ($dir = dir($path); false !== $entry = $dir->read(); ) { 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 === '..'); $isRef = ($entry === '.' || $entry === '..');
$isDir = $isRef || is_dir($path .'/'. $entry); $isDir = $isRef || is_dir($path .'/'. $entry);
if ( ((!$isDir && $list & FILE_LIST_FILES) || if ( ((!$isDir && $list & FILE_LIST_FILES) ||
+1 -1
View File
@@ -240,7 +240,7 @@ class filter extends basis_db
{ {
//$value->value = preg_replace('/(.*?)selected=.selected./', '$1', $value->value); //$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?]/', '$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 = preg_replace('/^\s*selected=.*?selected.*?\s*/', ' ', $value->value);
//$value->value = str_replace('selected=', '', $value->value); //$value->value = str_replace('selected=', '', $value->value);
+1 -1
View File
@@ -1532,7 +1532,7 @@ class WavFile
} else { } else {
// replace // replace
for ($i = 0; $i < $sampleBytes; ++$i) { for ($i = 0; $i < $sampleBytes; ++$i) {
$this->_samples{$offset + $i} = $sampleBinary{$i}; $this->_samples[$offset + $i] = $sampleBinary[$i];
} }
} }
+1 -1
View File
@@ -1435,7 +1435,7 @@ class Securimage
$length = strlen($code['display']); $length = strlen($code['display']);
for($i = 0; $i < $length; ++$i) { for($i = 0; $i < $length; ++$i) {
$letter = $code['display']{$i}; $letter = $code['display'][$i];
$letters[] = $letter; $letters[] = $letter;
} }
} }
+2 -1
View File
@@ -407,6 +407,7 @@ html {
background-color: var(--fhc-background); background-color: var(--fhc-background);
border-color: var(--fhc-border); border-color: var(--fhc-border);
padding: var(--fhc-cis-main-py) var(--fhc-cis-main-px); 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 { #cis-main .fa-arrow-up-right-from-square {
@@ -854,4 +855,4 @@ html {
#cis-main .modal-footer { #cis-main .modal-footer {
background-color: var(--fhc-secondary); background-color: var(--fhc-secondary);
} }
+25 -1
View File
@@ -11,6 +11,24 @@
html { html {
font-size: .875em; 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 { #appMenu {
width: 300px; width: 300px;
@@ -43,6 +61,12 @@ html {
flex: 1 1 auto; 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 { .tabulator-row.disabled.tabulator-row-odd .tabulator-cell {
color: var(--gray-400); color: var(--gray-400);
} }
@@ -160,4 +184,4 @@ html {
.tiny-90 div.tox.tox-tinymce { .tiny-90 div.tox.tox-tinymce {
height: 90% !important; height: 90% !important;
} }
+4
View File
@@ -16,11 +16,15 @@
padding: .5rem 1rem; padding: .5rem 1rem;
text-decoration: none; text-decoration: none;
} }
.fhc-app-menu li a.disabled {
--bs-link-opacity: .5;
}
.fhc-app-menu li a.active, .fhc-app-menu li a.active,
.fhc-app-menu li a:hover { .fhc-app-menu li a:hover {
--bs-link-color-rgb: var(--bs-link-hover-color-rgb); --bs-link-color-rgb: var(--bs-link-hover-color-rgb);
background: var(--surface-hover); background: var(--surface-hover);
} }
.fhc-app-menu li a.disabled,
.fhc-app-menu li a.active { .fhc-app-menu li a.active {
pointer-events: none; pointer-events: none;
} }
+32
View File
@@ -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 <https://www.gnu.org/licenses/>.
*/
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
};
}
};
+8
View File
@@ -46,6 +46,14 @@ export default {
url: url url: url
}; };
}, },
search(params, studiensemester_kurzbz) {
return {
method: 'post',
url: 'api/frontend/v1/stv/students/search/'
+ encodeURIComponent(studiensemester_kurzbz),
params
};
},
verband(relative_path) { verband(relative_path) {
return { return {
method: 'get', method: 'get',
+38
View File
@@ -148,6 +148,44 @@ const router = VueRouter.createRouter({
next(); 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(.*)*', path: '/:pathMatch(.*)*',
redirect: { redirect: {
+135
View File
@@ -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 <https://www.gnu.org/licenses/>.
*/
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 */`
<fhc-form class="stv-config" ref="form" @submit.prevent="update">
<bs-modal
ref="modal"
class="fade"
id="configModal"
dialog-class="modal-lg"
@hidden-bs-modal="tempValues = { ...modelValue }"
>
<template #title>{{ $p.t('ui/settings') }}</template>
<template #default>
<div class="d-flex flex-column gap-5">
<form-input
v-for="(value, key) in setup"
v-model="tempValues[key]"
v-bind="value.binding"
>
<option
v-for="(label, val) in value.options"
:key="val"
:value="val"
>{{ label }}</option>
</form-input>
</div>
</template>
<template #footer>
<button class="btn btn-primary" type="submit">
{{ $p.t('ui/speichern') }}
</button>
</template>
</bs-modal>
</fhc-form>`
};
+1
View File
@@ -64,5 +64,6 @@ export default {
{{ menu.description }} {{ menu.description }}
</a> </a>
</li> </li>
<slot />
</ul>` </ul>`
}; };
+1 -1
View File
@@ -316,7 +316,7 @@ export default {
template: /* html */` template: /* html */`
<div <div
class="fhc-calendar-base-grid" class="fhc-calendar-base-grid"
style="display:grid;width:100%;height:100%" style="display:grid;width:100%;height:100%;overflow:auto"
:style="'grid-template-' + axisRow + 's:auto' + (allDayEvents ? ' auto ' : ' ') + '1fr;grid-template-' + axisCol + 's:auto ' + styleGridCols" :style="'grid-template-' + axisRow + 's:auto' + (allDayEvents ? ' auto ' : ' ') + '1fr;grid-template-' + axisCol + 's:auto ' + styleGridCols"
> >
<div <div
@@ -124,6 +124,10 @@ export default {
? `${this.stg}/${this.semester}` ? `${this.stg}/${this.semester}`
: this.stg; : this.stg;
} }
else
{
this.selectedStudiengang = '';
}
this.filter = filter; this.filter = filter;
}, },
handleRowClicked(data) handleRowClicked(data)
@@ -163,6 +167,7 @@ export default {
const routeName = this.filter.emp ? 'byEmp' : 'byStg'; const routeName = this.filter.emp ? 'byEmp' : 'byStg';
const params = { stg }; const params = { stg };
params.semester = '';
if (semester !== null) if (semester !== null)
params.semester = semester; params.semester = semester;
if (studiensemester_kurzbz) if (studiensemester_kurzbz)
@@ -132,9 +132,10 @@ export default {
frozen: true frozen: true
} }
], ],
layout: 'fitDataFill', layout: 'fitDataStretchFrozen',
layoutColumnsOnNewData: false, layoutColumnsOnNewData: false,
height: '400', height: '400',
selectable: 1,
selectableRangeMode: 'click', selectableRangeMode: 'click',
index: 'message_id', index: 'message_id',
pagination: true, pagination: true,
@@ -147,7 +148,7 @@ export default {
dataTreeCollapseElement:"<i class='fas fa-minus-square'></i>", dataTreeCollapseElement:"<i class='fas fa-minus-square'></i>",
dataTreeChildIndent: 15, dataTreeChildIndent: 15,
dataTreeStartExpanded: false, dataTreeStartExpanded: false,
persistenceID: 'core-message', persistenceID: 'core-message-2025112401',
locale: 'de', locale: 'de',
"langs": { "langs": {
"de":{ //German language definition "de":{ //German language definition
+231 -12
View File
@@ -16,8 +16,10 @@
*/ */
import CoreSearchbar from "../searchbar/searchbar.js"; import CoreSearchbar from "../searchbar/searchbar.js";
import NavLanguage from "../navigation/Language.js";
import VerticalSplit from "../verticalsplit/verticalsplit.js"; import VerticalSplit from "../verticalsplit/verticalsplit.js";
import AppMenu from "../AppMenu.js"; import AppMenu from "../AppMenu.js";
import AppConfig from "../AppConfig.js";
import StvVerband from "./Studentenverwaltung/Verband.js"; import StvVerband from "./Studentenverwaltung/Verband.js";
import StvList from "./Studentenverwaltung/List.js"; import StvList from "./Studentenverwaltung/List.js";
import StvDetails from "./Studentenverwaltung/Details.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 ApiSearchbar from "../../api/factory/searchbar.js";
import ApiStv from "../../api/factory/stv.js"; import ApiStv from "../../api/factory/stv.js";
import ApiStvVerband from '../../api/factory/stv/verband.js'; import ApiStvVerband from '../../api/factory/stv/verband.js';
import ApiStvConfig from '../../api/factory/stv/config.js';
export default { export default {
name: 'Studentenverwaltung', name: 'Studentenverwaltung',
components: { components: {
CoreSearchbar, CoreSearchbar,
NavLanguage,
VerticalSplit, VerticalSplit,
AppMenu, AppMenu,
AppConfig,
StvVerband, StvVerband,
StvList, StvList,
StvDetails, StvDetails,
@@ -45,6 +50,8 @@ export default {
permissions: Object, permissions: Object,
stvRoot: String, stvRoot: String,
cisRoot: String, cisRoot: String,
avatarUrl: String,
logoutUrl: String,
activeAddons: String, // semicolon separated list of active addons activeAddons: String, // semicolon separated list of active addons
url_studiensemester_kurzbz: String, url_studiensemester_kurzbz: String,
url_mode: String, url_mode: String,
@@ -76,15 +83,19 @@ export default {
}, },
configShowAufnahmegruppen: this.config.showAufnahmegruppen, configShowAufnahmegruppen: this.config.showAufnahmegruppen,
configAllowUebernahmePunkte: this.config.allowUebernahmePunkte, configAllowUebernahmePunkte: this.config.allowUebernahmePunkte,
configUseReihungstestPunkte: this.config.useReihungstestPunkte configUseReihungstestPunkte: this.config.useReihungstestPunkte,
appConfig: Vue.computed(() => this.appconfig)
} }
}, },
data() { data() {
return { return {
appconfig: {},
configEndpoints: ApiStvConfig,
selected: [], selected: [],
searchbaroptions: { searchbaroptions: {
origin: 'stv', origin: 'stv',
calcheightonly: true, calcheightonly: true,
nolivesearch: true,
types: { types: {
student: Vue.computed(() => this.$p.t('search/type_student')), student: Vue.computed(() => this.$p.t('search/type_student')),
prestudent: Vue.computed(() => this.$p.t('search/type_prestudent')) prestudent: Vue.computed(() => this.$p.t('search/type_prestudent'))
@@ -123,6 +134,8 @@ export default {
studiengangKz: undefined, studiengangKz: undefined,
studiengangKuerzel: '', studiengangKuerzel: '',
studiensemesterKurzbz: this.defaultSemester, studiensemesterKurzbz: this.defaultSemester,
selected_semester: undefined,
selected_orgform: undefined,
lists: { lists: {
nations: [], nations: [],
sprachen: [], sprachen: [],
@@ -131,12 +144,60 @@ export default {
verbandEndpoint: ApiStvVerband 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: { watch: {
'url_studiensemester_kurzbz': function (newVal, oldVal) { 'url_studiensemester_kurzbz': function (newVal, oldVal) {
if (newVal !== oldVal) { if (newVal !== oldVal) {
this.studiensemesterKurzbz = newVal; this.studiensemesterKurzbz = newVal;
this.$refs.stvList.updateUrl(); if(this.$route.name === 'search')
this.$refs.details.reload(); {
this.handleSearchUrl();
}
else
{
this.$refs.stvList.updateUrl();
this.$refs.details.reload();
}
} }
}, },
'url_studiengang': function (newVal, oldVal) { 'url_studiengang': function (newVal, oldVal) {
@@ -146,6 +207,25 @@ export default {
}, },
'url_mode': function () { 'url_mode': function () {
this.handlePersonUrl(); 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: { methods: {
@@ -159,7 +239,7 @@ export default {
} }
}, },
buildPrestudentSearchResultLink(data) { buildPrestudentSearchResultLink(data) {
return this.$fhcApi.getUri( return this.$api.getUri(
'/studentenverwaltung' '/studentenverwaltung'
+ '/' + this.studiensemesterKurzbz + '/' + this.studiensemesterKurzbz
+ '/prestudent/' + '/prestudent/'
@@ -167,7 +247,7 @@ export default {
); );
}, },
buildStudentSearchResultLink(data) { buildStudentSearchResultLink(data) {
return this.$fhcApi.getUri( return this.$api.getUri(
'/studentenverwaltung' '/studentenverwaltung'
+ '/' + this.studiensemesterKurzbz + '/' + this.studiensemesterKurzbz
+ '/student/' + '/student/'
@@ -175,14 +255,14 @@ export default {
); );
}, },
buildPersonSearchResultLink(data) { buildPersonSearchResultLink(data) {
return this.$fhcApi.getUri( return this.$api.getUri(
'/studentenverwaltung' '/studentenverwaltung'
+ '/' + this.studiensemesterKurzbz + '/' + this.studiensemesterKurzbz
+ '/person/' + '/person/'
+ data.person_id + data.person_id
); );
}, },
onSelectVerband( {link, studiengang_kz}) { onSelectVerband({ link, studiengang_kz, semester, orgform_kurzbz }) {
let urlpath = String(link); let urlpath = String(link);
if (!urlpath.match(/\/prestudent/)) if (!urlpath.match(/\/prestudent/))
{ {
@@ -191,6 +271,8 @@ export default {
this.$refs.stvList.updateUrl(ApiStv.students.verband(urlpath)); this.$refs.stvList.updateUrl(ApiStv.students.verband(urlpath));
this.studiengangKz = studiengang_kz; this.studiengangKz = studiengang_kz;
this.selected_semester = semester;
this.selected_orgform = orgform_kurzbz;
const stg = this.lists.stgs.find((element) => { const stg = this.lists.stgs.find((element) => {
return (element.studiengang_kz === this.studiengangKz); return (element.studiengang_kz === this.studiengangKz);
}); });
@@ -223,9 +305,6 @@ export default {
studiensemester_kurzbz: v studiensemester_kurzbz: v
} }
}); });
this.$refs.stvList.updateUrl();
this.$refs.details.reload();
}, },
reloadList() { reloadList() {
this.$refs.stvList.reload(); this.$refs.stvList.reload();
@@ -249,6 +328,37 @@ export default {
ApiStv.students.person(this.$route.params.person_id, 'CURRENT_SEMESTER'), ApiStv.students.person(this.$route.params.person_id, 'CURRENT_SEMESTER'),
true 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() { 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() { created() {
@@ -376,10 +522,58 @@ export default {
<span class="fa-solid fa-table-list"></span> <span class="fa-solid fa-table-list"></span>
</button> </button>
<core-searchbar <core-searchbar
ref="searchbar"
:searchoptions="searchbaroptions" :searchoptions="searchbaroptions"
:searchfunction="searchfunction" :searchfunction="searchfunction"
class="searchbar position-relative w-100" class="searchbar position-relative w-100"
show-btn-submit
@submit.prevent="onSearch"
></core-searchbar> ></core-searchbar>
<div id="nav-user" class="dropdown">
<button
id="nav-user-btn"
class="btn btn-link rounded-0 py-0"
type="button"
data-bs-toggle="dropdown"
data-bs-target="#nav-user-menu"
aria-expanded="false"
aria-controls="nav-user-menu"
>
<img
:src="avatarUrl"
:alt="$p.t('profilUpdate/profilBild')"
class="bg-light avatar rounded-circle border border-light"
/>
</button>
<ul
ref="navUserDropdown"
class="dropdown-menu dropdown-menu-dark dropdown-menu-end rounded-0 text-center m-0"
aria-labelledby="nav-user-btn"
>
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#configModal"
>
{{ $p.t('ui/settings') }}
</button>
</li>
<li><hr class="dropdown-divider m-0"/></li>
<li>
<nav-language
item-class="dropdown-item border-left-dark"
/>
</li>
<li><hr class="dropdown-divider m-0"/></li>
<li>
<a class="dropdown-item" :href="logoutUrl">
{{ $p.t('ui/logout') }}
</a>
</li>
</ul>
</div>
</header> </header>
<div class="container-fluid overflow-hidden"> <div class="container-fluid overflow-hidden">
<div class="row h-100"> <div class="row h-100">
@@ -389,14 +583,38 @@ export default {
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" :aria-label="$p.t('ui/schliessen')"></button> <button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" :aria-label="$p.t('ui/schliessen')"></button>
</div> </div>
<div class="offcanvas-body"> <div class="offcanvas-body">
<app-menu app-identifier="stv" /> <app-menu app-identifier="stv">
<li class="dropend">
<a
class="dropdown-toggle"
href="#"
role="button"
data-bs-toggle="dropdown"
aria-expanded="false"
:class="{ disabled: !appMenuExtraItems.length }"
data-bs-popper-config='{"strategy":"fixed"}'
>
{{ $p.t('stv/grade_report') }}
</a>
<ul class="dropdown-menu p-0">
<li
v-for="(item, key) in appMenuExtraItems"
:key="key"
>
<a class="dropdown-item" :href="item.link" target="_blank">
{{ $p.t(item.description) }}
</a>
</li>
</ul>
</li>
</app-menu>
</div> </div>
</aside> </aside>
<nav id="sidebarMenu" class="bg-light offcanvas offcanvas-start col-md p-md-0 h-100"> <nav id="sidebarMenu" class="bg-light offcanvas offcanvas-start col-md p-md-0 h-100">
<div class="offcanvas-header justify-content-end px-1 d-md-none"> <div class="offcanvas-header justify-content-end px-1 d-md-none">
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" :aria-label="$p.t('ui/schliessen')"></button> <button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" :aria-label="$p.t('ui/schliessen')"></button>
</div> </div>
<stv-verband :preselectedKey="'' + studiengangKz" :endpoint="verbandEndpoint" @select-verband="onSelectVerband" class="col" style="height:0%"></stv-verband> <stv-verband :preselectedKey="studiengangKz ? '' + studiengangKz : null" :endpoint="verbandEndpoint" @select-verband="onSelectVerband" class="col" style="height:0%"></stv-verband>
<stv-studiensemester v-model:studiensemester-kurzbz="studiensemesterKurzbz" @update:studiensemester-kurzbz="studiensemesterChanged"></stv-studiensemester> <stv-studiensemester v-model:studiensemester-kurzbz="studiensemesterKurzbz" @update:studiensemester-kurzbz="studiensemesterChanged"></stv-studiensemester>
</nav> </nav>
<main class="col-md-8 ms-sm-auto col-lg-9 col-xl-10"> <main class="col-md-8 ms-sm-auto col-lg-9 col-xl-10">
@@ -411,5 +629,6 @@ export default {
</main> </main>
</div> </div>
</div> </div>
<app-config ref="config" v-model="appconfig" :endpoints="configEndpoints"></app-config>
</div>` </div>`
}; };
@@ -41,25 +41,34 @@ export default {
return Object.fromEntries(Object.entries(this.configStudents).filter(([ , value ]) => !value.showOnlyWithUid && !value.showOnlyWithUid)); 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: { 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() { reload() {
if (this.$refs.tabs?.$refs?.current?.reload) if (this.$refs.tabs?.$refs?.current?.reload)
this.$refs.tabs.$refs.current.reload(); this.$refs.tabs.$refs.current.reload();
} }
}, },
created() { created() {
this.$api this.loadConfig();
.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);
}, },
template: ` template: `
<div class="stv-details h-100 d-flex flex-column"> <div class="stv-details h-100 d-flex flex-column">
@@ -163,12 +163,12 @@ export default {
frozen: true frozen: true
}, },
], ],
layout: 'fitDataFill', layout: 'fitDataStretchFrozen',
layoutColumnsOnNewData: false, layoutColumnsOnNewData: false,
height: 'auto', height: 'auto',
minHeight: '200', minHeight: '200',
index: 'abschlusspruefung_id', index: 'abschlusspruefung_id',
persistenceID: 'stv-details-finalexam' persistenceID: 'stv-details-finalexam-2025112401'
}, },
tabulatorEvents: [ tabulatorEvents: [
{ {
@@ -107,10 +107,10 @@ export default {
frozen: true frozen: true
}, },
], ],
layout: 'fitDataFill', layout: 'fitDataStretchFrozen',
height: '500', height: '500',
index: 'anrechnung_id', index: 'anrechnung_id',
persistenceID: 'stv-details-anrechnungen' persistenceID: 'stv-details-anrechnungen-2025112401'
}, },
tabulatorEvents: [ tabulatorEvents: [
{ {
@@ -120,12 +120,12 @@ export default {
frozen: true frozen: true
} }
], ],
layout: 'fitDataFill', layout: 'fitDataStretchFrozen',
layoutColumnsOnNewData: false, layoutColumnsOnNewData: false,
height: 'auto', height: 'auto',
minHeight: 200, minHeight: 200,
index: 'aufnahmetermin_id', index: 'aufnahmetermin_id',
persistenceID: 'stv-details-table_admission-dates' persistenceID: 'stv-details-table_admission-dates-2025112401'
}, },
tabulatorEvents: [ tabulatorEvents: [
{ {
@@ -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*/ `
<div class="stv-details-combine-people h-100 pb-3">
<div v-if="!this.viewLoaded">
<h4>Personen zusammenlegen</h4>
<div v-if="this.modelValue.length">
<div v-if="this.modelValue.length == 2">
<p>{{$p.t('stv', 'question_combine_people', { person1: detailStringPerson1, person2: detailStringPerson2 })}}</p>
<button class="btn btn-primary" @click="combinePeople">{{$p.t('ui', 'ok')}}</button>
</div>
<div v-else>
ungültige Anzahl: {{this.modelValue.length}} <!-- should not be seen anymore-->
</div>
</div>
</div>
<div v-else>
<button class="btn btn-secondary" @click="goBack">{{$p.t('ui', 'cancel')}}</button>
</div>
<!-- Iframe-Section -->
<iframe
v-if="iframeUrl"
:src="iframeUrl"
class="w-100 mt-4 border-0"
style="height: 600px;"
></iframe>
</div>
`
};
@@ -71,10 +71,10 @@ export default {
frozen: true frozen: true
}, },
], ],
layout: 'fitColumns', layout: 'fitDataStretchFrozen',
layoutColumnsOnNewData: false, layoutColumnsOnNewData: false,
height: 200, height: 200,
persistenceID: 'core-mobility-purpose' persistenceID: 'core-mobility-purpose-2025112401'
}, },
tabulatorEvents: [ tabulatorEvents: [
{ {
@@ -69,10 +69,10 @@ export default {
frozen: true frozen: true
}, },
], ],
layout: 'fitColumns', layout: 'fitDataStretchFrozen',
layoutColumnsOnNewData: false, layoutColumnsOnNewData: false,
height: 200, height: 200,
persistenceID: 'core-mobility-support' persistenceID: 'core-mobility-support-2025112401'
}, },
tabulatorEvents: [ tabulatorEvents: [
{ {
@@ -109,12 +109,12 @@ export default {
frozen: true frozen: true
}, },
], ],
layout: 'fitDataFill', layout: 'fitDataStretchFrozen',
layoutColumnsOnNewData: false, layoutColumnsOnNewData: false,
height: 'auto', height: 'auto',
minHeight: 200, minHeight: 200,
index: 'bisio_id', index: 'bisio_id',
persistenceID: 'stv-details-table_mobiliy' persistenceID: 'stv-details-table_mobiliy-2025112401'
}, },
tabulatorEvents: [ tabulatorEvents: [
{ {
@@ -217,9 +217,13 @@ export default {
}, },
columns, columns,
height: '100%', height: '100%',
layout: 'fitDataStretchFrozen',
selectable: 1, selectable: 1,
selectableRangeMode: 'click', selectableRangeMode: 'click',
persistenceID: 'stv-details-noten-zeugnis' persistenceID: 'stv-details-noten-zeugnis-2025112401',
persistence:{
columns: ["width", "visible", "frozen"]
}
}; };
} }
}, },
@@ -287,4 +291,4 @@ export default {
<zeugnis-documents :data="grade" :list="config.documentslist"></zeugnis-documents> <zeugnis-documents :data="grade" :list="config.documentslist"></zeugnis-documents>
</Teleport> </Teleport>
</div>` </div>`
}; };
@@ -227,15 +227,15 @@ export default{
const rowData = row.getData(); const rowData = row.getData();
if (this.dataMeldestichtag && this.dataMeldestichtag > rowData.datum) 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, layoutColumnsOnNewData: false,
height: 'auto', height: 'auto',
selectable: false, selectable: false,
index: 'statusId', index: 'statusId',
persistenceID: 'stv-multistatus' persistenceID: 'stv-multistatus-2025112401'
}, },
tabulatorEvents: [ tabulatorEvents: [
{ {
@@ -40,6 +40,9 @@ export default {
} }
return lehreinheiten; return lehreinheiten;
},
firmenverwaltungLink(){
return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'vilesci/stammdaten/firma_frameset.html';
} }
}, },
props: { props: {
@@ -255,18 +258,25 @@ export default {
<div class="row mb-3"> <div class="row mb-3">
<form-input <div class="col-10">
container-class="stv-details-projektarbeit-firma" <form-input
:label="$p.t('projektarbeit', 'firma')" container-class="stv-details-projektarbeit-firma"
type="autocomplete" :label="$p.t('projektarbeit', 'firma')"
optionLabel="name" type="autocomplete"
v-model="formData.firma" optionLabel="name"
name="firma" v-model="formData.firma"
:suggestions="filteredFirmen" name="firma"
@complete="searchFirma" :suggestions="filteredFirmen"
:min-length="3" @complete="searchFirma"
> :min-length="3"
</form-input> >
</form-input>
</div>
<div class="col-2 align-content-center">
<a :href="firmenverwaltungLink" target="_blank">
{{ $p.t('projektarbeit', 'zurFirmenverwaltung') }}
</a>
</div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
@@ -240,7 +240,7 @@ export default {
frozen: true frozen: true
}, },
], ],
//layout: 'fitDataFill', layout: 'fitDataStretchFrozen',
height: 'auto', height: 'auto',
minHeight: '200', minHeight: '200',
selectable: 1, selectable: 1,
@@ -248,7 +248,7 @@ export default {
persistence:{ persistence:{
columns: true, //persist column layout columns: true, //persist column layout
}, },
persistenceID: 'stv-details-projektarbeit' persistenceID: 'stv-details-projektarbeit-2025112401'
} }
return options; return options;
} }
@@ -396,8 +396,8 @@ export default {
<template #footer> <template #footer>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{$p.t('ui', 'abbrechen')}}</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{$p.t('ui', 'abbrechen')}}</button>
<button v-if="statusNew" class="btn btn-primary" @click="addNewProjektarbeit()"> {{$p.t('ui', 'speichern')}}</button> <button v-if="statusNew" class="btn btn-primary" @click="addNewProjektarbeit()"> {{$p.t('ui', 'speichern')}}</button>
<button v-if="!statusNew && activeTab == 'details'" class="btn btn-primary" @click="updateProjektarbeit()"> {{$p.t('ui', 'speichern')}}</button> <button v-if="!statusNew && activeTab == 'details'" class="btn btn-primary" @click="updateProjektarbeit()"> {{$p.t('ui', 'speichern')}}</button>
</template> </template>
</bs-modal> </bs-modal>
@@ -115,7 +115,7 @@ export default {
frozen: true frozen: true
}, },
], ],
//layout: 'fitDataFill', layout: 'fitDataStretchFrozen',
layoutColumnsOnNewData: false, layoutColumnsOnNewData: false,
height: 'auto', height: 'auto',
minHeight: '100', minHeight: '100',
@@ -125,7 +125,7 @@ export default {
persistence:{ persistence:{
columns: true, //persist column layout columns: true, //persist column layout
}, },
persistenceID: 'stv-details-projektbetreuer' persistenceID: 'stv-details-projektbetreuer-2025112401'
}, },
tabulatorEvents: [ tabulatorEvents: [
{ {
@@ -46,8 +46,6 @@ export default{
{title: "Punkte", field: "punkte", visible: false}, {title: "Punkte", field: "punkte", visible: false},
{ {
title: 'Aktionen', field: 'actions', title: 'Aktionen', field: 'actions',
minWidth: 150,
maxWidth: 150,
formatter: (cell, formatterParams, onRendered) => { formatter: (cell, formatterParams, onRendered) => {
let container = document.createElement('div'); let container = document.createElement('div');
container.className = "d-flex gap-2"; container.className = "d-flex gap-2";
@@ -93,7 +91,7 @@ export default{
layoutColumnsOnNewData: false, layoutColumnsOnNewData: false,
height: 'auto', height: 'auto',
index: 'pruefung_id', index: 'pruefung_id',
persistenceID: 'stv-details-pruefung-list' persistenceID: 'stv-details-pruefung-list-2025112402'
}, },
tabulatorEvents: [ tabulatorEvents: [
{ {
@@ -148,7 +146,6 @@ export default{
listMas: [], listMas: [],
listMarks: [], listMarks: [],
zeugnisData: [], zeugnisData: [],
checkData:[],
filter: false, filter: false,
statusNew: true, statusNew: true,
isStartDropDown: false, isStartDropDown: false,
@@ -181,7 +178,7 @@ export default{
this.pruefungData.student_uid = this.uid; this.pruefungData.student_uid = this.uid;
this.pruefungData.note = 9; 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.pruefungstyp_kurzbz = null;
if(lv_id){ if(lv_id){
this.pruefungData.lehrveranstaltung_id = lv_id; this.pruefungData.lehrveranstaltung_id = lv_id;
@@ -193,7 +190,7 @@ export default{
this.isStartDropDown = false; this.isStartDropDown = false;
this.loadPruefung(pruefung_id).then(() => { this.loadPruefung(pruefung_id).then(() => {
this.pruefungData.note = 9; 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.pruefungstyp_kurzbz = null;
this.pruefungData.anmerkung = null; this.pruefungData.anmerkung = null;
this.prepareDropdowns(); this.prepareDropdowns();
@@ -229,9 +226,8 @@ export default{
return this.$refs.examData return this.$refs.examData
.call(ApiStvExam.addPruefung(this.pruefungData)) .call(ApiStvExam.addPruefung(this.pruefungData))
.then(response => { .then(response => {
this.checkData = response.data; if (response.data)
if (this.checkData === 2 || this.checkData === 5) this.$fhcAlert.alertDefault('info', 'Info', response.data, true);
this.$fhcAlert.alertInfo(this.$p.t('exam', 'hinweis_changeAfterExamDate'));
else else
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave'));
this.hideModal('pruefungModal'); this.hideModal('pruefungModal');
@@ -243,12 +239,13 @@ export default{
}); });
}, },
updatePruefung(pruefung_id){ updatePruefung(pruefung_id){
this.checkChangeAfterExamDate();
return this.$refs.examData return this.$refs.examData
.call(ApiStvExam.updatePruefung(pruefung_id, this.pruefungData)) .call(ApiStvExam.updatePruefung(pruefung_id, this.pruefungData))
.then(response => { .then(response => {
this.checkData = response.data; if (response.data)
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); this.$fhcAlert.alertDefault('info', 'Info', response.data, true);
else
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave'));
this.hideModal('pruefungModal'); this.hideModal('pruefungModal');
this.resetModal(); this.resetModal();
}).catch(this.$fhcAlert.handleSystemError) }).catch(this.$fhcAlert.handleSystemError)
@@ -266,27 +263,6 @@ export default{
else else
this.showHint = false; 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) { deletePruefung(pruefung_id) {
return this.$api return this.$api
.call(ApiStvExam.deletePruefung(pruefung_id)) .call(ApiStvExam.deletePruefung(pruefung_id))
@@ -534,6 +510,7 @@ export default{
container-class="mb-3" container-class="mb-3"
type="DatePicker" type="DatePicker"
v-model="pruefungData.datum" v-model="pruefungData.datum"
model-type="yyyy-MM-dd"
name="datum" name="datum"
:label="$p.t('global/datum')" :label="$p.t('global/datum')"
auto-apply auto-apply
@@ -2,6 +2,8 @@ import {CoreFilterCmpt} from "../../filter/Filter.js";
import ListNew from './List/New.js'; import ListNew from './List/New.js';
import ListFilter from './List/Filter.js'; import ListFilter from './List/Filter.js';
import { capitalize } from '../../../helpers/StringHelpers.js';
import draggable from '../../../directives/draggable.js'; import draggable from '../../../directives/draggable.js';
export default { export default {
@@ -133,7 +135,17 @@ export default {
{ {
return Promise.resolve({ data: []}); 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) => { ajaxResponse: (url, params, response) => {
return response?.data; return response?.data;
@@ -175,7 +187,7 @@ export default {
count: 0, count: 0,
filteredcount: 0, filteredcount: 0,
selectedcount: 0, selectedcount: 0,
currentEndpointRawUrl: '' currentEndpoint: null
} }
}, },
computed: { computed: {
@@ -228,7 +240,84 @@ export default {
return "StudentList_" + today + ".csv"; return "StudentList_" + today + ".csv";
} }
}, },
watch: {
'$p.user_language.value'(n, o) {
if (n !== o && o !== undefined && this.$refs.table.tableBuilt) {
this.translateTabulator();
}
}
},
methods: { 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() { reload() {
this.$refs.table.reloadTable(); this.$refs.table.reloadTable();
}, },
@@ -273,16 +362,20 @@ export default {
updateUrl(endpoint, first) { updateUrl(endpoint, first) {
this.lastSelected = first ? undefined : this.selected; 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}; endpoint = { url: '' };
} }
else if( endpoint.url === undefined ) else if( endpoint === undefined )
{ {
endpoint.url = this.currentEndpointRawUrl; endpoint = JSON.parse(JSON.stringify(this.currentEndpoint));
} else }
else
{ {
this.currentEndpointRawUrl = endpoint.url; this.currentEndpoint = JSON.parse(JSON.stringify(endpoint));
} }
endpoint.url = endpoint.url.replace( endpoint.url = endpoint.url.replace(
@@ -290,20 +383,25 @@ export default {
encodeURIComponent(this.currentSemester) encodeURIComponent(this.currentSemester)
); );
const params = {}; const params = (endpoint?.params !== undefined) ? endpoint.params : {};
if (this.filter.length) let method = (endpoint?.method !== undefined) ? endpoint.method : 'get';
if (this.filter.length && !endpoint.url.match(/\/search\//))
{
params.filter = this.filter; 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.tableBuilt) {
if (!this.$refs.table.tabulator) { if (this.$refs.table.tabulator) {
this.tabulatorOptions.ajaxURL = endpoint.url;
this.tabulatorOptions.ajaxParams = params;
} else
this.$refs.table.tabulator.on("tableBuilt", () => { this.$refs.table.tabulator.on("tableBuilt", () => {
this.$refs.table.tabulator.setData(endpoint.url, params); this.$refs.table.tabulator.setData(endpoint.url, params, method);
}); });
}
} else } else
this.$refs.table.tabulator.setData(endpoint.url, params); this.$refs.table.tabulator.setData(endpoint.url, params, method);
}, },
dragCleanup(evt) { dragCleanup(evt) {
if (evt.dataTransfer.dropEffect == 'none') if (evt.dataTransfer.dropEffect == 'none')
@@ -402,6 +500,7 @@ export default {
*/` */`
:new-btn-label="$p.t('stv/action_new')" :new-btn-label="$p.t('stv/action_new')"
@click:new="actionNewPrestudent" @click:new="actionNewPrestudent"
@table-built="translateTabulator"
> >
<template #filter> <template #filter>
<div class="card"> <div class="card">
@@ -16,11 +16,17 @@ export default {
inject: { inject: {
$reloadList: { $reloadList: {
from: '$reloadList', from: '$reloadList',
required: true default: () => {}
}, },
currentSemester: { currentSemester: {
from: 'currentSemester', from: 'currentSemester',
required: true required: true
},
appConfig: {
from: 'appConfig',
default: {
number_displayed_past_studiensemester: 5
}
} }
}, },
emits: [ emits: [
@@ -52,6 +58,9 @@ export default {
return this.nodes.filter(node => this.favorites.list.includes(node.key)); return this.nodes.filter(node => this.favorites.list.includes(node.key));
return this.nodes; return this.nodes;
},
noSemReloadNodes() {
return this.nodes.reduce(this.mapNodesToNoSemReloadNodes, []);
} }
}, },
watch: { watch: {
@@ -59,6 +68,14 @@ export default {
if (newVal !== oldVal) { if (newVal !== oldVal) {
this.setPreselection(); this.setPreselection();
} }
},
'appConfig.number_displayed_past_studiensemester'(newVal, oldVal) {
if (oldVal !== undefined) {
this.noSemReloadNodes.forEach(node => {
delete node.children;
this.onExpandTreeNode(node);
});
}
} }
}, },
methods: { methods: {
@@ -114,7 +131,14 @@ export default {
}, },
onSelectTreeNode(node) { onSelectTreeNode(node) {
if (node.data.link) 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) { mapResultToTreeData(el) {
const cp = { const cp = {
@@ -187,22 +211,25 @@ export default {
if (!currentNode) if (!currentNode)
return; return;
const currentSelectedKey = Object.keys(this.selectedKey).find(Boolean); if(this.selectedKey)
if (currentSelectedKey) { {
if (currentSelectedKey == currentKey) const currentSelectedKey = Object.keys(this.selectedKey).find(Boolean);
return; if (currentSelectedKey) {
/** if (currentSelectedKey == currentKey)
* Do not select a new entry if the current is a child of the new one. return;
* 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 * Do not select a new entry if the current is a child of the new one.
* routes yet) * 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
const isChild = this.findNodeByKey( * routes yet)
currentSelectedKey, */
currentNode.children const isChild = this.findNodeByKey(
); currentSelectedKey,
if (isChild) currentNode.children || []
return; );
if (isChild)
return;
}
} }
for (let i = 1; i < parts.length; i++) for (let i = 1; i < parts.length; i++)
+59 -3
View File
@@ -33,7 +33,8 @@ export default {
data() { data() {
return { return {
current: null, current: null,
tabs: {} tabs: {},
count: null
} }
}, },
computed: { computed: {
@@ -113,10 +114,12 @@ export default {
}; };
} }
if (Array.isArray(config)) if (Array.isArray(config)) {
config.forEach((item, key) => _addToTabs(key, item)); config.forEach((item, key) => _addToTabs(key, item));
else }
else {
Object.entries(config).forEach(([key, item]) => _addToTabs(key, item)); Object.entries(config).forEach(([key, item]) => _addToTabs(key, item));
}
if (this.current === null || !tabs[this.current]) { if (this.current === null || !tabs[this.current]) {
if (tabs[this.default]) if (tabs[this.default])
@@ -129,6 +132,57 @@ export default {
updateSuffix() { updateSuffix() {
this.getTabSuffix(this.currentTab); 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) { async getTabSuffix(tab) {
if (!tab.value.showSuffix) { if (!tab.value.showSuffix) {
return; return;
@@ -151,9 +205,11 @@ export default {
}, },
mounted() { mounted() {
this.getTabSuffixes(); this.getTabSuffixes();
this.removeInvalidCountTabs();
}, },
updated() { updated() {
this.getTabSuffixes(); this.getTabSuffixes();
this.removeInvalidCountTabs();
}, },
template: ` template: `
<template v-if="useprimevue"> <template v-if="useprimevue">
@@ -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 <https://www.gnu.org/licenses/>.
*/
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*/`
<div class="navigation-language d-flex justify-content-center align-items-center flex-nowrap overflow-hidden">
<button
v-for="lang in languages"
:class="[itemClass, {[activeClass]: $p.user_language.value == lang.sprache}]"
:selected="$p.user_language.value == lang.sprache"
@click.prevent="onChange(lang.sprache)"
>
{{ lang.bezeichnung }}
</button>
</div>`
};
+43 -14
View File
@@ -23,7 +23,17 @@ export default {
mergedStudent, mergedStudent,
mergedPerson mergedPerson
}, },
props: [ "searchoptions", "searchfunction" ], props: {
searchoptions: {
type: Object,
required: true
},
searchfunction: {
type: Function,
required: true
},
showBtnSubmit: Boolean
},
provide() { provide() {
return { return {
query: Vue.computed(() => this.lastQuery) query: Vue.computed(() => this.lastQuery)
@@ -102,11 +112,22 @@ export default {
> >
<button <button
v-if="searchsettings.searchstr" v-if="searchsettings.searchstr"
type="button"
class="searchbar_input_clear btn btn-outline-secondary" class="searchbar_input_clear btn btn-outline-secondary"
@click="clearInput" @click="clearInput"
@focusin.stop
> >
<i class="fas fa-close"></i> <i class="fas fa-close"></i>
</button> </button>
<button
v-if="showBtnSubmit"
type="submit"
class="btn btn-primary"
:title="$p.t('search/submit')"
:aria-label="$p.t('search/submit')"
>
<i class="fas fa-search"></i>
</button>
<button <button
data-bs-toggle="collapse" data-bs-toggle="collapse"
data-bs-target="#searchSettings" data-bs-target="#searchSettings"
@@ -219,12 +240,12 @@ export default {
}); });
} }
}, },
methods: { methods: {
clearInput() { clearInput() {
this.searchsettings.searchstr = ""; this.searchsettings.searchstr = "";
this.hideresult(); this.hideresult();
this.$refs.input.focus() this.$refs.input.focus();
}, },
getInitiallySelectedTypes() { getInitiallySelectedTypes() {
let result = false; let result = false;
if (this.searchoptions.origin) { if (this.searchoptions.origin) {
@@ -283,13 +304,9 @@ export default {
this.calcSearchResultHeight(); this.calcSearchResultHeight();
}, },
search: function() { search: function() {
if( this.searchtimer !== null ) { if(this.searchoptions?.nolivesearch === true) return;
clearTimeout(this.searchtimer);
} this.abort();
if (this.abortController) {
this.abortController.abort();
this.abortController = null;
}
if( this.searchsettings.searchstr.length >= 2 ) { if( this.searchsettings.searchstr.length >= 2 ) {
this.calcSearchResultExtent(); this.calcSearchResultExtent();
this.searchtimer = setTimeout( this.searchtimer = setTimeout(
@@ -300,6 +317,16 @@ export default {
this.showresult = false; this.showresult = false;
} }
}, },
abort() {
if (this.searchtimer !== null) {
clearTimeout(this.searchtimer);
}
if (this.abortController) {
this.abortController.abort();
this.abortController = null;
}
this.searchresult = [];
},
callsearchapi: function() { callsearchapi: function() {
this.error = null; this.error = null;
this.searchresult.splice(0, this.searchresult.length); this.searchresult.splice(0, this.searchresult.length);
@@ -392,6 +419,8 @@ export default {
window.removeEventListener('resize', this.calcSearchResultExtent); window.removeEventListener('resize', this.calcSearchResultExtent);
}, },
showsearchresult: function() { showsearchresult: function() {
if(this.searchoptions?.nolivesearch === true) return;
if( this.searchsettings.searchstr.length >= 2 ) { if( this.searchsettings.searchstr.length >= 2 ) {
this.showresult = true; this.showresult = true;
window.addEventListener('resize', this.calcSearchResultExtent); window.addEventListener('resize', this.calcSearchResultExtent);
+1
View File
@@ -86,6 +86,7 @@ require_once('dbupdate_3.4/40314_electronic_onboarding_anbindung_ida.php');
require_once('dbupdate_3.4/47972_pruefungsverwaltung_ects_angabe.php'); require_once('dbupdate_3.4/47972_pruefungsverwaltung_ects_angabe.php');
require_once('dbupdate_3.4/62063_lv_evaluierung.php'); require_once('dbupdate_3.4/62063_lv_evaluierung.php');
require_once('dbupdate_3.4/67490_studstatus_suche_abort_controller_haengt.php'); require_once('dbupdate_3.4/67490_studstatus_suche_abort_controller_haengt.php');
require_once('dbupdate_3.4/68744_StV_settings.php');
// *** Pruefung und hinzufuegen der neuen Attribute und Tabellen // *** Pruefung und hinzufuegen der neuen Attribute und Tabellen
echo '<H2>Pruefe Tabellen und Attribute!</H2>'; echo '<H2>Pruefe Tabellen und Attribute!</H2>';
@@ -0,0 +1,16 @@
<?php
if (!defined('DB_NAME')) exit('No direct script access allowed');
// Add new name type in public.tbl_variablenname
if ($result = @$db->db_query("SELECT 1 FROM public.tbl_variablenname WHERE name = 'stv_font_size';"))
{
if ($db->db_num_rows($result) == 0)
{
$qry = "INSERT INTO public.tbl_variablenname(name, defaultwert) VALUES('stv_font_size', null);";
if (!$db->db_query($qry))
echo '<strong>public.tbl_variablenname '.$db->db_last_error().'</strong><br>';
else
echo 'public.tbl_variablenname: Added name "stv_font_size"<br>';
}
}
+23
View File
@@ -529,6 +529,29 @@ $filters = array(
', ',
'oe_kurzbz' => null, 'oe_kurzbz' => null,
), ),
array(
'app' => 'infocenter',
'dataset_name' => 'onboarding',
'filter_kurzbz' => 'InfoCenterOnboarding',
'description' => '{Alle}',
'sort' => 1,
'default_filter' => true,
'filter' => '
{
"name": "Electronic Onboarding - Alle",
"columns": [
{"name": "PersonId"},
{"name": "Vorname"},
{"name": "Nachname"},
{"name": "LockUser"},
{"name": "HoldDate"},
{"name": "Rueckstellgrund"}
],
"filters": []
}
',
'oe_kurzbz' => null,
),
array( array(
'app' => 'infocenter', 'app' => 'infocenter',
'dataset_name' => 'aufgenommen', 'dataset_name' => 'aufgenommen',
-3
View File
@@ -1,3 +0,0 @@
<?php
phpinfo();
?>
+662
View File
@@ -1795,6 +1795,66 @@ $phrases = array(
) )
) )
), ),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'logout',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Logout',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Logout',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'settings',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Einstellungen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Settings',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'settings_saved',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Einstellungen gespeichert',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Settings saved',
'description' => '',
'insertvon' => 'system'
)
)
),
array( array(
'app' => 'core', 'app' => 'core',
'category' => 'ui', 'category' => 'ui',
@@ -2542,6 +2602,46 @@ $phrases = array(
) )
) )
), ),
array(
'app' => 'core',
'category' => 'person',
'phrase' => 'email_private',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'EMail (Privat)',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'email (private)',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'person',
'phrase' => 'email_intern',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'EMail (Intern)',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'email (intern)',
'description' => '',
'insertvon' => 'system'
)
)
),
array( array(
'app' => 'core', 'app' => 'core',
'category' => 'person', 'category' => 'person',
@@ -3124,6 +3224,26 @@ $phrases = array(
) )
) )
), ),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'orgform',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'OrgForm',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'orgform',
'description' => '',
'insertvon' => 'system'
)
)
),
array( array(
'app' => 'core', 'app' => 'core',
'category' => 'lehre', 'category' => 'lehre',
@@ -3164,6 +3284,26 @@ $phrases = array(
) )
) )
), ),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'grp',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Grp.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'grp.',
'description' => '',
'insertvon' => 'system'
)
)
),
array( array(
'app' => 'core', 'app' => 'core',
'category' => 'lehre', 'category' => 'lehre',
@@ -3504,6 +3644,26 @@ $phrases = array(
) )
) )
), ),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'sem',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Sem.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'sem.',
'description' => '',
'insertvon' => 'system'
)
)
),
array( array(
'app' => 'core', 'app' => 'core',
'category' => 'lehre', 'category' => 'lehre',
@@ -3786,6 +3946,66 @@ $phrases = array(
) )
) )
), ),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'studiengang_kz',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Studiengang KZ',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Study program no',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'verb',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Verb.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'assoc.',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'dual_short',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Dual',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'dual',
'description' => '',
'insertvon' => 'system'
)
)
),
//********************** INFOCENTER/infocenter //********************** INFOCENTER/infocenter
array( array(
'app' => 'infocenter', 'app' => 'infocenter',
@@ -6421,6 +6641,26 @@ The invoice will be sent to you again. <u><strong>The amount is only to be trans
) )
) )
), ),
array(
'app' => 'core',
'category' => 'global',
'phrase' => 'status_bestaetigung',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Status Bestätigung',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Status confirmation',
'description' => '',
'insertvon' => 'system'
)
)
),
array( array(
'app' => 'core', 'app' => 'core',
'category' => 'global', 'category' => 'global',
@@ -38680,6 +38920,166 @@ array(
) )
), ),
//**************************** CORE/stv //**************************** CORE/stv
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'settings_no_displayed_past_sem',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Anzahl angezeigter vergangener Studiensemester',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Number of past semesters of study displayed',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'settings_fontsize',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Zoom',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Zoom',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'settings_fontsize_xx-small',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Sehr Klein',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Very Small',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'settings_fontsize_x-small',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Kleiner',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Smaller',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'settings_fontsize_small',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Klein',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Small',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'settings_fontsize_normal',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Normal',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Normal',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'settings_fontsize_big',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Groß',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Big',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'settings_fontsize_huge',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Sehr groß',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Very big',
'description' => '',
'insertvon' => 'system'
)
)
),
array( array(
'app' => 'core', 'app' => 'core',
'category' => 'stv', 'category' => 'stv',
@@ -38700,6 +39100,86 @@ array(
) )
) )
), ),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'notes_person',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Anmerkungen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'notes',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'notes_prestudent',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Anmerkung Pre',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'note Pre',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'aufnahmegruppe_kurzbz',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Aufnahmegruppe',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'admission group',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'mentor',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Mentor',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'mentor',
'description' => '',
'insertvon' => 'system'
)
)
),
array( array(
'app' => 'core', 'app' => 'core',
'category' => 'stv', 'category' => 'stv',
@@ -38880,6 +39360,86 @@ array(
) )
) )
), ),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'grade_report',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Notenspiegel',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Grade report',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'grade_report_xls',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Notenspiegel EXCEL',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Grade report EXCEL',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'grade_report_xls_extended',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Notenspiegel erweitert EXCEL',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Grade report extended EXCEL',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'grade_report_html',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Notenspiegel HTML',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Grade report HTML',
'description' => '',
'insertvon' => 'system'
)
)
),
array( array(
'app' => 'core', 'app' => 'core',
'category' => 'stv', 'category' => 'stv',
@@ -49211,6 +49771,26 @@ and represent the current state of research on the topic. The prescribed citatio
// FHC-4 Finetuning END // FHC-4 Finetuning END
//**************************** CORE/search //**************************** CORE/search
array(
'app' => 'core',
'category' => 'search',
'phrase' => 'submit',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'suchen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'search',
'description' => '',
'insertvon' => 'system'
)
)
),
array( array(
'app' => 'core', 'app' => 'core',
'category' => 'search', 'category' => 'search',
@@ -51645,6 +52225,26 @@ I have been informed that I am under no obligation to consent to the transmissio
) )
) )
), ),
array(
'app' => 'core',
'category' => 'projektarbeit',
'phrase' => 'zurFirmenverwaltung',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Zur Firmenverwaltung',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Company management',
'description' => '',
'insertvon' => 'system'
)
)
),
// FHC-4 Projektarbeiten & Vertraege ENDE // FHC-4 Projektarbeiten & Vertraege ENDE
// ### DOKUMENTE ERSTELLEN PHRASEN START ### // ### DOKUMENTE ERSTELLEN PHRASEN START ###
array( array(
@@ -52197,6 +52797,68 @@ I have been informed that I am under no obligation to consent to the transmissio
) )
), ),
// ### DOKUMENTE ERSTELLEN PHRASEN END ### // ### DOKUMENTE ERSTELLEN PHRASEN END ###
// ### Personen zusammenlegen Phrasen BEGIN
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'tab_combine_people',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Personen zusammenlegen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Combine People',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'question_combine_people',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Die Personen {person1} und {person2} zusammenlegen?',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Merge the persons {person1} and {person2}?',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'error_combinePeople_samePerson',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Keine Zusammenlegung möglich bei identischer Person ID!',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'No merging possible with identical person ID"',
'description' => '',
'insertvon' => 'system'
)
)
),
// ### Personen zusammenlegen Phrasen END
); );
+3 -3
View File
@@ -71,7 +71,7 @@ $fileTmpName = null;
$fileMimeType = null; $fileMimeType = null;
// Constants // Constants
$L_CSV_N_COLS = 10; // Number of columns of the CSV file $L_CSV_N_COLS = 9; // Number of columns of the CSV file
$L_ERROR = "Error"; $L_ERROR = "Error";
$L_WARNING = "Warning"; $L_WARNING = "Warning";
$L_INFO = "Info"; $L_INFO = "Info";
@@ -477,8 +477,8 @@ if (!$errorOccurred && $dataPosted)
Feldtrenner: ;<br> Feldtrenner: ;<br>
Texttrenner: "<br> Texttrenner: "<br>
Felder:<br> Felder:<br>
<pre>Nachname;Vorname;UID/PersKZ;Studiengang;Betrag;Überweisungsdatum <pre>Nachname;Vorname;Gebdatum;UID/PersKZ;Studiengang;Betrag;IBAN;BIC;Bankname
Dylan;Bob;1234567;MEE;750;03.10.2016</pre> Dylan;Bob;12.12.2000;1234567;MEE;750;ATXXXX;BBAWAATWW;BAWAG PSK</pre>
</td> </td>
</tr> </tr>
<tr> <tr>