This commit is contained in:
Cristina
2025-09-03 13:06:47 +02:00
45 changed files with 1494 additions and 333 deletions
+23 -20
View File
@@ -75,16 +75,16 @@ $route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/inout/outgoing'] = 'api/
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/inout/gemeinsamestudien'] = 'api/frontend/v1/stv/Students/getGemeinsamestudien';
// (studiengang_kz)/prestudent[/(studiensemester_kurzbz)[/(filter)[/(otherfilter)]]]
$route['api/frontend/v1/stv/[sS]tudents/(:num)/prestudent'] = 'api/frontend/v1/stv/Students/getPrestudents/$1';
$route['api/frontend/v1/stv/[sS]tudents/(:num)/prestudent/([WS]S[0-9]{4})'] = 'api/frontend/v1/stv/Students/getPrestudents/$1/$2';
$route['api/frontend/v1/stv/[sS]tudents/(:num)/prestudent/([WS]S[0-9]{4})/(:any)'] = 'api/frontend/v1/stv/Students/getPrestudents/$1/$2/$3';
$route['api/frontend/v1/stv/[sS]tudents/(:num)/prestudent/([WS]S[0-9]{4})/(:any)/(:any)'] = 'api/frontend/v1/stv/Students/getPrestudents/$1/$2/$4';
$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/prestudent'] = 'api/frontend/v1/stv/Students/getPrestudents/$1';
$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/prestudent/([WS]S[0-9]{4})'] = 'api/frontend/v1/stv/Students/getPrestudents/$1/$2';
$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/prestudent/([WS]S[0-9]{4})/(:any)'] = 'api/frontend/v1/stv/Students/getPrestudents/$1/$2/$3';
$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/prestudent/([WS]S[0-9]{4})/(:any)/(:any)'] = 'api/frontend/v1/stv/Students/getPrestudents/$1/$2/$4';
// (studiengang_kz)/(orgform)/prestudent[/(studiensemester_kurzbz)[/(filter)[/(otherfilter)]]]
$route['api/frontend/v1/stv/[sS]tudents/(:num)/([A-Z]{2,3})/prestudent'] = 'api/frontend/v1/stv/Students/getPrestudentsOrgform/$1/$2';
$route['api/frontend/v1/stv/[sS]tudents/(:num)/([A-Z]{2,3})/prestudent/([WS]S[0-9]{4})'] = 'api/frontend/v1/stv/Students/getPrestudentsOrgform/$1/$2/$3';
$route['api/frontend/v1/stv/[sS]tudents/(:num)/([A-Z]{2,3})/prestudent/([WS]S[0-9]{4})/(:any)'] = 'api/frontend/v1/stv/Students/getPrestudentsOrgform/$1/$2/$3/$4';
$route['api/frontend/v1/stv/[sS]tudents/(:num)/([A-Z]{2,3})/prestudent/([WS]S[0-9]{4})/(:any)/(:any)'] = 'api/frontend/v1/stv/Students/getPrestudentsOrgform/$1/$2/$3/$5';
$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/([A-Z]{2,3})/prestudent'] = 'api/frontend/v1/stv/Students/getPrestudentsOrgform/$1/$2';
$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/([A-Z]{2,3})/prestudent/([WS]S[0-9]{4})'] = 'api/frontend/v1/stv/Students/getPrestudentsOrgform/$1/$2/$3';
$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/([A-Z]{2,3})/prestudent/([WS]S[0-9]{4})/(:any)'] = 'api/frontend/v1/stv/Students/getPrestudentsOrgform/$1/$2/$3/$4';
$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/([A-Z]{2,3})/prestudent/([WS]S[0-9]{4})/(:any)/(:any)'] = 'api/frontend/v1/stv/Students/getPrestudentsOrgform/$1/$2/$3/$5';
// (studiensemester_kurzbz)/(studiengang_kz)/(semester)/grp/(gruppe)
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/(:num)/grp/(:any)'] = 'api/frontend/v1/stv/Students/getStudentsSpezialgruppe/$1/$2/$3/$4';
@@ -111,23 +111,26 @@ $route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/prestudent/(:num)'] = 'a
// // (studiensemester_kurzbz)/person/(person_id)
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/person/(:num)'] = 'api/frontend/v1/stv/Students/getPerson/$1/$2';
// load routes from extensions
$subdir = 'application/config/extensions';
$dirlist = scandir($subdir);
// load routes from extensions, also look for environment-specific configs
$subdirs = ['application/config/extensions', 'application/config/' . ENVIRONMENT . '/extensions'];
if ($dirlist)
foreach($subdirs as $subdir)
{
$files = array_diff($dirlist, array('.','..'));
foreach ($files as &$item)
$dirlist = scandir($subdir);
if ($dirlist)
{
if (is_dir($subdir . DIRECTORY_SEPARATOR . $item))
{
$routes_file = $subdir . DIRECTORY_SEPARATOR . $item . DIRECTORY_SEPARATOR . 'routes.php';
$files = array_diff($dirlist, array('.','..'));
if (file_exists($routes_file))
foreach ($files as &$item)
{
if (is_dir($subdir . DIRECTORY_SEPARATOR . $item))
{
require($routes_file);
$routes_file = $subdir . DIRECTORY_SEPARATOR . $item . DIRECTORY_SEPARATOR . 'routes.php';
if (file_exists($routes_file))
{
require($routes_file);
}
}
}
}
+4
View File
@@ -58,6 +58,10 @@ $config['tabs'] =
//if true, Anrechnungen can be added and edited in tab Anrechnungen
'editableAnrechnungen' => false,
],
'notes' => [
//if true, the count of Messages will be shown in the header of the Tab Messages
'showCountNotes' => true
]
];
// List of fields to show when ZGV_DOKTOR_ANZEIGEN is defined
@@ -269,6 +269,8 @@ class LvMenu extends FHCAPI_Controller
'lehrfach_id'=>$lehrfach_id,
'lektor_der_lv'=>$lektor_der_lv,
'lehrfach_oe_kurzbz_arr'=>$lehrfach_oe_kurzbz_arr,
'permissionLib' => &$this->PermissionLib,
'phrasesLib' => &$this->PhrasesLib
];
Events::trigger('lvMenuBuild',
@@ -60,7 +60,11 @@ class BetriebsmittelP extends FHCAPI_Controller
public function getAllBetriebsmittel($type_id, $id)
{
$result = $this->BetriebsmittelpersonModel->getBetriebsmittelData($id, $type_id);
$betriebsmitteltypes = null;
if ($this->input->get('betriebsmitteltypes') !== null && !isEmptyArray($this->input->get('betriebsmitteltypes')))
$betriebsmitteltypes = $this->input->get('betriebsmitteltypes');
$result = $this->BetriebsmittelpersonModel->getBetriebsmittelData($id, $type_id, $betriebsmitteltypes);
if (isError($result)) {
$this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL);
@@ -370,6 +374,12 @@ class BetriebsmittelP extends FHCAPI_Controller
$this->load->model('ressource/Betriebsmitteltyp_model', 'BetriebsmitteltypModel');
$this->BetriebsmitteltypModel->addOrder('beschreibung', 'ASC');
if ($this->input->get('betriebsmitteltypes') !== null && !isEmptyArray($this->input->get('betriebsmitteltypes')))
{
$this->BetriebsmitteltypModel->db->where_in('betriebsmitteltyp', $this->input->get('betriebsmitteltypes'));
}
$result = $this->BetriebsmitteltypModel->load(); // load All
if (isError($result)) {
@@ -418,6 +418,10 @@ class Messages extends FHCAPI_Controller
}
$data = $this->getDataOrTerminateWithError($result);
if (count($data) < 1)
{
$this->terminateWithError('Error: Messages API no person_id found.');
}
$person = current($data);
return $person->person_id;
@@ -432,8 +436,12 @@ class Messages extends FHCAPI_Controller
);
$data = $this->getDataOrTerminateWithError($result);
if (count($data) < 1)
{
$this->terminateWithError('Error: Messages API no prestudent_id found.');
}
$student = current($data);
// $this->terminateWithError($student->prestudent_id, self::ERROR_TYPE_GENERAL);
return $student->prestudent_id;
}
@@ -18,6 +18,7 @@ class NotizPerson extends Notiz_Controller
'loadDokumente' => ['admin:r', 'assistenz:r'],
'getMitarbeiter' => ['admin:r', 'assistenz:r'],
'isBerechtigt' => ['admin:r', 'assistenz:r'],
'getCountNotes' => ['admin:r', 'assistenz:r'],
]);
}
@@ -62,10 +62,15 @@ class Config extends FHCAPI_Controller
'component' => './Stv/Studentenverwaltung/Details/Details.js',
'config' => $config['details']
];
$result['notes'] = [
'title' => $this->p->t('stv', 'tab_notes'),
'component' => './Stv/Studentenverwaltung/Details/Notizen.js'
'component' => './Stv/Studentenverwaltung/Details/Notizen.js',
'config' => $config['notes'],
'showSuffix' => ($config['notes']['showCountNotes'] ?? false),
'suffixhelper' => APP_ROOT . 'public/js/helpers/Stv/Studentenverwaltung/Details/Notizen/NotizenSuffixHelper.js'
];
$result['contact'] = [
'title' => $this->p->t('stv', 'tab_contact'),
'component' => './Stv/Studentenverwaltung/Details/Kontakt.js',
@@ -35,8 +35,6 @@ class Favorites extends FHCAPI_Controller
// Load models
$this->load->model('system/Variable_model', 'VariableModel');
// TODO(chris): variable table might be to small to store favorites!
}
public function index()
@@ -62,6 +60,17 @@ class Favorites extends FHCAPI_Controller
$favorites = $this->input->post('favorites');
$removed = [];
while (strlen($favorites) > 64) {
$favObj = json_decode($favorites);
if (!$favObj->list)
break;
$removed[] = array_shift($favObj->list);
$favorites = json_encode($favObj);
}
if ($removed)
$this->addMeta('removed', $removed);
$result = $this->VariableModel->setVariable(getAuthUID(), 'stv_favorites', $favorites);
$this->getDataOrTerminateWithError($result);
@@ -16,7 +16,8 @@ class Notiz extends Notiz_Controller
'updateNotiz' => ['admin:rw', 'assistenz:rw'], // TODO(manu): self::PERM_LOGGED
'deleteNotiz' => ['admin:r', 'assistenz:r'],
'loadDokumente' => ['admin:r', 'assistenz:r'],
'getMitarbeiter' => ['admin:r', 'assistenz:r']
'getMitarbeiter' => ['admin:r', 'assistenz:r'],
'getCountNotes' => ['admin:r', 'assistenz:r'],
]);
//Load Models
@@ -24,7 +24,6 @@ class Status extends FHCAPI_Controller
'updateStatus' => ['admin:rw', 'assistenz:rw'],
'advanceStatus' => ['admin:rw', 'assistenz:rw'],
'confirmStatus' => ['admin:rw', 'assistenz:rw'],
]);
//Load Models
@@ -440,9 +439,10 @@ class Status extends FHCAPI_Controller
]);
if (!$this->form_validation->run())
{
$this->terminateWithValidationErrors($this->form_validation->error_array());
}
$this->load->library('PrestudentLib');
$this->db->trans_start();
@@ -628,8 +628,9 @@ class Status extends FHCAPI_Controller
]);
if (!$this->form_validation->run())
{
$this->terminateWithValidationErrors($this->form_validation->error_array());
}
// Start DB transaction
$this->db->trans_start();
@@ -106,6 +106,7 @@ class Student extends FHCAPI_Controller
$this->PrestudentModel->addSelect('p.staatsbuergerschaft');
$this->PrestudentModel->addSelect('p.matr_nr');
$this->PrestudentModel->addSelect('p.anrede');
$this->PrestudentModel->addSelect('p.zugangscode');
if (defined('ACTIVE_ADDONS') && strpos(ACTIVE_ADDONS, 'bewerbung') !== false) {
$this->PrestudentModel->addSelect(
@@ -693,7 +694,7 @@ class Student extends FHCAPI_Controller
return $result;
}*/
$this->terminateWithSuccess(true);
return success(true);
}
public function requiredIfNotPersonId($value)
@@ -709,4 +710,9 @@ class Student extends FHCAPI_Controller
return true;
return !!$value;
}
public function isValidDate($value)
{
return isValidDate($value);
}
}
+73 -24
View File
@@ -11,6 +11,7 @@ class UHSTAT1 extends FHC_Controller
const CODEX_UNKNOWN_YEAR = 9999;
const CODEX_UNKNOWN_NATION = 'XXX';
const CODEX_UNKNOWN_BILDUNGMAX = 999;
const CODEX_EXCLUDED_NATIONS = ['ZZZ'];
const LOWER_BOUNDARY_YEARS = 160;
const UPPER_BOUNDARY_YEARS = 20;
@@ -32,8 +33,7 @@ class UHSTAT1 extends FHC_Controller
$this->load->library('PermissionLib');
// load models
$this->load->model('codex/Oehbeitrag_model', 'OehbeitragModel');
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$this->load->model('person/Benutzer_model', 'BenutzerModel');
$this->load->model('system/Sprache_model', 'SpracheModel');
$this->load->model('codex/Abschluss_model', 'AbschlussModel');
$this->load->model('codex/Uhstat1daten_model', 'Uhstat1datenModel');
@@ -104,7 +104,7 @@ class UHSTAT1 extends FHC_Controller
{
$saved = false;
$person_id = $this->_getValidPersonId('sui');
$person_id = $this->_getUHSTATPersonId('sui');
$this->form_validation->set_error_delimiters('<span class="text-danger">', '</span>');
@@ -245,7 +245,7 @@ class UHSTAT1 extends FHC_Controller
// uhstat data can only be deleted with permission
if (!$this->_checkPermission('suid')) show_error('no permission');
$person_id = $this->_getValidPersonId('suid');
$person_id = $this->_getUHSTATPersonId('suid');
$uhstat1datenRes = $this->Uhstat1datenModel->delete(
array('person_id' => $person_id)
@@ -287,13 +287,17 @@ class UHSTAT1 extends FHC_Controller
*/
private function _getFormMetaData()
{
$person_id = $this->_getValidPersonId('s');
$person_id = $this->_getUHSTATPersonId('s');
// read only display param
$readOnly = $this->input->get('readOnly');
// depending on permissions, editing or deleting is possible
$editPermission = $this->_checkPermission('sui');
// checking permissions for form
// saving is possible if there permission or student log in (but not from application tool)
$savePermission = $this->_checkPermission('sui') || ($this->_getUserPersonId() && !$this->_getApplicationToolPersonId());
// deleting only possible with permission
$deletePermission = $this->_checkPermission('suid');
$languageIdx = $this->_getLanguageIndex();
@@ -304,7 +308,7 @@ class UHSTAT1 extends FHC_Controller
'abschluss_nicht_oesterreich' => array(),
'jahre' => array(),
'person_id' => $person_id,
'editPermission' => $editPermission,
'savePermission' => $savePermission,
'deletePermission' => $deletePermission,
'readOnly' => $readOnly
);
@@ -336,15 +340,19 @@ class UHSTAT1 extends FHC_Controller
if (hasData($nationRes))
{
$dropdownNations = [];
$nations = getData($nationRes);
// put austria in beginning of selection
foreach ($nations as $nation)
{
if ($nation->nation_code == self::CODEX_OESTERREICH) array_unshift($nations, $nation);
// put austria in beginning of selection
if ($nation->nation_code == self::CODEX_OESTERREICH)
array_unshift($dropdownNations, $nation);
elseif (!in_array($nation->nation_code, self::CODEX_EXCLUDED_NATIONS)) // add nation if not excluded
$dropdownNations[] = $nation;
}
$formMetaData['nation'] = $nations;
$formMetaData['nation'] = $dropdownNations;
}
// get abschluss list
@@ -386,7 +394,7 @@ class UHSTAT1 extends FHC_Controller
*/
private function _getUHSTAT1Data()
{
$person_id = $this->_getValidPersonId('s');
$person_id = $this->_getUHSTATPersonId('s');
$this->Uhstat1datenModel->addSelect(
implode(', ', array_keys($this->_uhstat1Fields))
@@ -417,29 +425,70 @@ class UHSTAT1 extends FHC_Controller
}
/**
* Gets Id of person having permissions to manage UHSTAT1 data.
* Can be passed as parameter or be in session.
* Gets Id of person, for which UHSTAT1 data is edited.
* Can be passed as parameter, id of logged in person, or be in session.
* @param berechtigungsArt type of permission (suid)
* @return int person_id
*/
private function _getValidPersonId($berechtigungsArt)
private function _getUHSTATPersonId($berechtigungsArt)
{
// if coming from bewerbungstool - person id is in session (person must be logged in bewerbungstool)
$applicationToolPersonId = $this->_getApplicationToolPersonId();
if (isset($applicationToolPersonId) && is_numeric($applicationToolPersonId)) return $applicationToolPersonId;
// if successfully logged in
$loggedInPersonId = $this->_getUserPersonId();
if (isset($loggedInPersonId) && is_numeric($loggedInPersonId))
{
// if person id passed directly...
$person_id = $this->input->post('person_id');
if (!isset($person_id)) $person_id = $this->input->get('person_id');
if (isset($person_id))
{
if (!is_numeric($person_id)) show_error("invalid person id");
// ...check if there is a permission for editing UHSTAT1 data
if ($this->_checkPermission($berechtigungsArt)) return $person_id;
}
// if no id passed, use logged in person id
return $loggedInPersonId;
}
show_error("No permission");
}
/**
* Gets person Id if there is a application tool login.
* @return person Id or null
*/
private function _getApplicationToolPersonId()
{
// if coming from aplication tool - person id is in session (person must be logged in bewerbungstool)
if (isset($_SESSION[self::PERSON_ID_SESSION_INDEX])
&& is_numeric($_SESSION[self::PERSON_ID_SESSION_INDEX])
&& isset($_SESSION[self::LOGIN_SESSION_INDEX])
)
return $_SESSION[self::PERSON_ID_SESSION_INDEX];
// if person id passed directly...
$person_id = $this->input->post('person_id');
if (!isset($person_id)) $person_id = $this->input->get('person_id');
return null;
}
if (!isset($person_id) || !is_numeric($person_id)) show_error("invalid person id");
// ...check if there is a permission for editing UHSTAT1 data
if ($this->_checkPermission($berechtigungsArt)) return $person_id;
show_error("No permission");
/**
* Gets person Id if there is a user login.
* @return person Id or null
*/
private function _getUserPersonId()
{
$loggedInPersonId = getAuthPersonId();
if (isset($loggedInPersonId) && is_numeric($loggedInPersonId))
{
// check if the the user is a student and if the benutzer is active
$this->BenutzerModel->addSelect('1');
$res = $this->BenutzerModel->loadWhere(["public.tbl_benutzer.person_id" => $loggedInPersonId, "public.tbl_benutzer.aktiv" => TRUE]);
if (hasData($res)) return $loggedInPersonId;
}
return null;
}
/**
@@ -1275,7 +1275,6 @@ class InfoCenter extends Auth_Controller
'nachname' => $this->input->post('nachname'),
'titelpost' => isEmptyString($this->input->post('titelpost')) ? null : $this->input->post('titelpost'),
'gebdatum' => isEmptyString($this->input->post('gebdatum')) ? null : date("Y-m-d", strtotime($this->input->post('gebdatum'))),
'svnr' => isEmptyString($this->input->post('svnr')) ? null : $this->input->post('svnr'),
'staatsbuergerschaft' => isEmptyString($this->input->post('buergerschaft')) ? null : $this->input->post('buergerschaft'),
'geschlecht' => $this->input->post('geschlecht'),
'geburtsnation' => isEmptyString($this->input->post('gebnation')) ? null : $this->input->post('gebnation'),
@@ -1816,7 +1815,7 @@ class InfoCenter extends Auth_Controller
}
/**
* Loads all necessary Person data: Stammdaten (name, svnr, contact, ...), Dokumente, Logs and Notizen
* Loads all necessary Person data: Stammdaten (name, contact, ...), Dokumente, Logs and Notizen
* @param $person_id
* @return array
*/
+17
View File
@@ -21,6 +21,7 @@ abstract class Notiz_Controller extends FHCAPI_Controller
'loadDokumente' => self::DEFAULT_PERMISSION_R,
'getMitarbeiter' => self::DEFAULT_PERMISSION_R,
'isBerechtigt' => self::DEFAULT_PERMISSION_R,
'getCountNotes' => self::DEFAULT_PERMISSION_R,
];
if(!is_array($permissions))
@@ -459,4 +460,20 @@ abstract class Notiz_Controller extends FHCAPI_Controller
return $this->terminateWithSuccess($result);
}
public function getCountNotes($person_id)
{
$this->NotizzuordnungModel->addSelect('COUNT(*) AS anzahl', false);
$result = $this->NotizzuordnungModel->loadWhere(
array('person_id' => $person_id)
);
if (isError($result)) {
$this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL);
}
$anzahl = current(getData($result));
return $this->terminateWithSuccess($anzahl->anzahl ?: 0);
}
}
+1
View File
@@ -122,6 +122,7 @@ class PhrasesLib
$tmpText = substr($tmpText, 0, strlen($tmpText) - 4);
}
}
$tmpText = str_replace(['<span class="caps">', '</span>'], '', $tmpText);
$result->retval[$i]->text = $tmpText;
}
@@ -97,7 +97,7 @@ class Betriebsmittelperson_model extends DB_Model
return $this->loadWhere($condition);
}
public function getBetriebsmittelData($id, $type_id)
public function getBetriebsmittelData($id, $type_id, $betriesmitteltypes = null)
{
switch ($type_id) {
case 'person_id':
@@ -113,6 +113,15 @@ class Betriebsmittelperson_model extends DB_Model
return error("ID nicht gültig");
}
$cond .= " = ? ";
$params[] = $id;
if ($betriesmitteltypes && !isEmptyArray($betriesmitteltypes))
{
$cond .= " AND bm.betriebsmitteltyp IN ?";
$params[] = $betriesmitteltypes;
}
$query = "
SELECT
bm.nummer, bmp.person_id, bm.betriebsmitteltyp, bmp.anmerkung as anmerkung,
@@ -126,9 +135,9 @@ class Betriebsmittelperson_model extends DB_Model
JOIN
wawi.tbl_betriebsmittel bm ON (bmp.betriebsmittel_id = bm.betriebsmittel_id)
WHERE
" . $cond . " = ? ";
" . $cond;
return $this->execQuery($query, array($id));
return $this->execQuery($query, $params);
}
/**
+3 -3
View File
@@ -26,7 +26,7 @@ $vater_bildungsstaat = isset($uhstatData->vater_bildungsstaat) ? $uhstatData->va
$vater_bildungmax = isset($uhstatData->vater_bildungmax) ? $uhstatData->vater_bildungmax : set_value('vater_bildungmax');
$readOnly = isset($formMetaData['readOnly']);
$disabled = $readOnly ? ' disabled' : '';
$editPermission = isset($formMetaData['editPermission']) && $formMetaData['editPermission'] === true;
$savePermission = isset($formMetaData['savePermission']) && $formMetaData['savePermission'] === true;
$deletePermission = isset($formMetaData['deletePermission']) && $formMetaData['deletePermission'] === true;
$saved = isset($saved) && $saved === true;
?>
@@ -51,7 +51,7 @@ $saved = isset($saved) && $saved === true;
<?php echo $this->p->t('uhstat', 'uhstat1EinleitungSvnrtext') ?>
</p>
<br>
<?php if ($editPermission): ?>
<?php if ($savePermission): ?>
<?php if (isset($successMessage) && !isEmptyString($successMessage)): ?>
<div class="alert alert-success" id="uhstat_success_alert">
<button type="button" class="close" data-dismiss="alert">x</button>
@@ -288,7 +288,7 @@ $saved = isset($saved) && $saved === true;
</div>
</div>
</fieldset>
<?php if ($editPermission && !$readOnly): ?>
<?php if ($savePermission && !$readOnly): ?>
<br>
<fieldset>
<div class="form-group">
@@ -32,12 +32,6 @@
<div class='stammdaten' id="gebdatum"><?php echo date_format(date_create($stammdaten->gebdatum), 'd.m.Y') ?></div>
</td>
</tr>
<tr>
<td><strong><?php echo ucfirst($this->p->t('person','svnr')) ?></strong></td>
<td>
<div class='stammdaten' id="svnr"><?php echo $stammdaten->svnr ?></div>
</td>
</tr>
<tr>
<td><strong><?php echo ucfirst($this->p->t('person','staatsbuergerschaft')) ?></strong></td>
<td>
@@ -285,15 +285,16 @@ function showHideBezeichnungDropDown()
if (dd.options[dd.selectedIndex].value == 'DienstV')
{
var str = '<select name="bezeichnung" class="dd_breit">';
str += '<option value="Eheschließung">a) Eigene Eheschließung (3 Tage)</option>';
str += '<option value="Eheschließung">a) Eigene Eheschließung oder Verpartnerung (3 Tage)</option>';
str += '<option value="Geburt eigenes Kind">b) Geburt eines Kindes der Ehefrau/Lebensgefährtin (2 Tage)</option>';
str += '<option value="Heirat Kind/Geschwister">c) Eheschließung eines Kindes/eigener Geschwister (1 Tag)</option>';
str += '<option value="Heirat Kind/Geschwister">c) Eheschließung oder Verpartnerung eines Kindes/eigener Geschwister (1 Tag)</option>';
str += '<option value="Eigene Sponsion/Promotion">d) Teilnahme an eigener Sponsion/Promotion (1 Tag)</option>';
str += '<option value="Lebensbedr. Erkrankung P/K/E">e) Lebensbedrohliche Erkrankung Partner/Kinder/Eltern (3 Tage)</option>';
str += '<option value="Ableben P/K/E">f) Ableben Partner/Kinder/Elternteil (3 Tage)</option>';
str += '<option value="Bestattung G/S/G">g) Teilnahme an Bestattung Geschwister/Schwiegereltern/eigener Großeltern (1 Tag)</option>';
str += '<option value="Wohnungswechsel">h) Wohnungswechsel in eigenen Haushalt (2 Tage)</option>';
str += '<option value="Bundesheer">i) Einberufung Bundesheer</option>';
str += '<option value="Volksschultag">j) erster Volksschultag (1 Tag)</option>';
str += '</select>';
sp.innerHTML = str;
+10 -1
View File
@@ -3553,6 +3553,15 @@ function StudentZeugnisDokumentArchivieren()
xml = 'abschlussdokument_lehrgaenge.xml.php';
break;
case 'microcredentialzertifikat_1':
case 'microcredentialzertifikat_2':
case 'microcredentialzertifikat_3':
case 'microcredential_1':
case 'microcredential_2':
case 'microcredential_3':
xml = 'microcredential.xml.php';
break;
default:
alert('Das Archivieren fuer diesen Dokumenttyp wird derzeit nicht unterstuetzt');
return
@@ -4783,7 +4792,7 @@ function StudentNotenMoveFromAntrag()
var uid = document.getElementById('student-detail-textbox-uid').value;
req.add('student_uid', uid);
var txt = "?";
for(var q in req.parms) {
txt = txt+'&'+req.parms[q].name+'='+encodeURIComponent(req.parms[q].value);
+4 -4
View File
@@ -244,10 +244,10 @@ function checkZeilenUmbruch()
if(defined('CIS_LEHRVERANSTALTUNG_ANWESENHEIT_ANZEIGEN') && CIS_LEHRVERANSTALTUNG_ANWESENHEIT_ANZEIGEN && $angemeldet
&& (!defined('CIS_LEHRVERANSTALTUNG_ANWESENHEIT_ANZEIGEN_STG') || in_array($lv->studiengang_kz, unserialize(CIS_LEHRVERANSTALTUNG_ANWESENHEIT_ANZEIGEN_STG)))
&& (!defined('CIS_LEHRVERANSTALTUNG_ANWESENHEIT_ANZEIGEN_LVA') || in_array($lv->lehrveranstaltung_id, unserialize(CIS_LEHRVERANSTALTUNG_ANWESENHEIT_ANZEIGEN_LVA)))
&& ($rechte->isBerechtigt('extension/anw_ent_admin')
|| $rechte->isBerechtigt('extension/anwesenheit_lektor')
|| $rechte->isBerechtigt('extension/anwesenheit_student')
|| $rechte->isBerechtigt('extension/anwesenheit_admin')))
&& ($rechte->isBerechtigt('extension/anw_r_ent_assistenz')
|| $rechte->isBerechtigt('extension/anw_r_lektor')
|| $rechte->isBerechtigt('extension/anw_r_student')
|| $rechte->isBerechtigt('extension/anw_r_full_assistenz')))
{
$link='';
$text='';
+4
View File
@@ -3973,6 +3973,10 @@
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
}
.p-tabview-panel .btn-close,
.p-tabview-panel .carousel-indicators [data-bs-target] {
box-sizing: content-box;
}
.p-toolbar {
background: #efefef;
+10 -4
View File
@@ -16,10 +16,13 @@
*/
export default {
getAllBetriebsmittel(type, id) {
getAllBetriebsmittel(type, id, betriebsmitteltypes) {
return {
method: 'get',
url: 'api/frontend/v1/betriebsmittel/betriebsmittelP/getAllBetriebsmittel/' + type + '/' + id
url: 'api/frontend/v1/betriebsmittel/betriebsmittelP/getAllBetriebsmittel/' + type + '/' + id,
params: {
betriebsmitteltypes
}
};
},
addNewBetriebsmittel(person_id, params) {
@@ -48,10 +51,13 @@ export default {
url: 'api/frontend/v1/betriebsmittel/betriebsmittelP/deleteBetriebsmittel/' + betriebsmittelperson_id
};
},
getTypenBetriebsmittel() {
getTypenBetriebsmittel(betriebsmitteltypes) {
return {
method: 'get',
url: 'api/frontend/v1/betriebsmittel/betriebsmittelP/getTypenBetriebsmittel/'
url: 'api/frontend/v1/betriebsmittel/betriebsmittelP/getTypenBetriebsmittel/',
params: {
betriebsmitteltypes
}
};
},
loadInventarliste(query) {
+6
View File
@@ -83,5 +83,11 @@ export default {
method: 'get',
url: 'api/frontend/v1/notiz/notizPerson/isBerechtigt/'
};
},
getCountNotes(person_id){
return {
method: 'get',
url: 'api/frontend/v1/notiz/notizPerson/getCountNotes/' + person_id
};
}
};
@@ -29,14 +29,24 @@ export default {
uid: {
type: [Number, String],
required: true
}
},
/** List of types to allow for creation */
betriebsmittelTypes: {
type: Array,
default: null
},
/**
* If true: only show the types specified in 'betriebsmittelTypes'.
* If false: show all available types.
*/
filterByProvidedTypes: Boolean
},
data() {
return {
tabulatorOptions: {
ajaxURL: 'dummy',
ajaxRequestFunc: () => this.$api.call(
this.endpoint.getAllBetriebsmittel(this.typeId, this.id)
this.endpoint.getAllBetriebsmittel(this.typeId, this.id, (this.filterByProvidedTypes ? this.betriebsmittelTypes : null))
),
ajaxResponse: (url, params, response) => response.data,
columns: [
@@ -294,7 +304,7 @@ export default {
},
created() {
return this.$api
.call(this.endpoint.getTypenBetriebsmittel())
.call(this.endpoint.getTypenBetriebsmittel(this.betriebsmittelTypes))
.then(result => {
this.listBetriebsmitteltyp = result.data;
})
+18 -5
View File
@@ -3,7 +3,8 @@
export default {
name: 'BootstrapModal',
data: () => ({
modal: null
modal: null,
fullscreen: false
}),
props: {
backdrop: {
@@ -34,6 +35,10 @@ export default {
footerClass: {
type: [String,Array,Object],
default: ''
},
allowFullscreenExpand: {
type: Boolean,
default: false
}
},
emits: [
@@ -58,6 +63,9 @@ export default {
},
toggle() {
return this.modal.toggle();
},
toggleFullscreen() {
this.fullscreen = !this.fullscreen
}
},
mounted() {
@@ -122,13 +130,18 @@ export default {
});
});
},
template: `<div ref="modal" class="bootstrap-modal modal" tabindex="-1" @[\`hide.bs.modal\`]="$emit('hideBsModal')" @[\`hidden.bs.modal\`]="$emit('hiddenBsModal')" @[\`hidePrevented.bs.modal\`]="$emit('hidePreventedBsModal')" @[\`show.bs.modal\`]="$emit('showBsModal')" >
<div class="modal-dialog" :class="dialogClass">
template: `<div ref="modal" class="bootstrap-modal modal" tabindex="-1" @[\`hide.bs.modal\`]="$emit('hideBsModal')" @[\`hidden.bs.modal\`]="$emit('hiddenBsModal')" @[\`hidePrevented.bs.modal\`]="$emit('hidePreventedBsModal')" @[\`show.bs.modal\`]="$emit('showBsModal')" @[\`shown.bs.modal\`]="$emit('shownBsModal')">
<div class="modal-dialog" :class="fullscreen ? 'modal-fullscreen' : dialogClass">
<div class="modal-content">
<div v-if="$slots.title" class="modal-header" :class="headerClass">
<h5 class="modal-title"><slot name="title"/></h5>
<slot name="popoutButton"></slot>
<button v-if="!noCloseBtn" type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<div class="d-flex align-items-center ms-auto">
<button type="button" class="btn ms-auto" style="filter: invert(1)" v-if="allowFullscreenExpand" @click="toggleFullscreen">
<i v-if="!fullscreen" class="fa-solid fa-expand"></i>
<i v-else class="fa-solid fa-compress"></i>
</button>
<button v-if="!noCloseBtn" type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<slot name="modal-header-content"></slot>
</div>
<div class="modal-body" :class="bodyClass">
+9 -4
View File
@@ -44,11 +44,16 @@ export default {
},
watch: {
currentDate() {
this.rangeOffset = this.currentDate.startOf('day').diff(this.focusDate.startOf('day'), 'days').days;
if (this.rangeOffset) {
this.$refs.view.$refs.grid.disableAutoScroll();
if (this.currentDate.locale != this.focusDate.locale) {
this.focusDate = this.currentDate;
this.$emit('update:range', this.range);
this.$refs.slider.slidePages(this.rangeOffset).then(this.updatePage);
} else {
this.rangeOffset = this.currentDate.startOf('day').diff(this.focusDate.startOf('day'), 'days').days;
if (this.rangeOffset) {
this.$refs.view.$refs.grid.disableAutoScroll();
this.$emit('update:range', this.range);
this.$refs.slider.slidePages(this.rangeOffset).then(this.updatePage);
}
}
}
},
+8 -3
View File
@@ -47,10 +47,15 @@ export default {
},
watch: {
currentDate() {
this.rangeOffset = this.currentDate.startOf('day').diff(this.focusDate.startOf('day'), 'days').days;
if (this.rangeOffset) {
if (this.currentDate.locale != this.focusDate.locale) {
this.focusDate = this.currentDate;
this.$emit('update:range', this.range);
this.$refs.slider.slidePages(this.rangeOffset).then(this.updatePage);
} else {
this.rangeOffset = this.currentDate.startOf('day').diff(this.focusDate.startOf('day'), 'days').days;
if (this.rangeOffset) {
this.$emit('update:range', this.range);
this.$refs.slider.slidePages(this.rangeOffset).then(this.updatePage);
}
}
}
},
+2 -1
View File
@@ -3,6 +3,7 @@ import FhcFragment from "../Fragment.js";
let _uuid = {};
export default {
name: "FormInput",
inheritAttrs: false,
components: {
FhcFragment
@@ -220,7 +221,7 @@ export default {
if (this.tag == 'VueDatePicker' && !this._.components.VueDatePicker) {
this._.components.VueDatePicker = Vue.defineAsyncComponent(() => import("../vueDatepicker.js.php"));
} else if (this.tag == 'PvAutocomplete' && !this._.components.PvAutocomplete) {
this._.components.PvAutocomplete = Vue.defineAsyncComponent(() => import(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + "/public/js/components/primevue/autocomplete/autocomplete.esm.min.js"));
this._.components.PvAutocomplete = primevue.autocomplete;
} else if (this.tag == 'UploadImage' && !this._.components.UploadImage) {
this._.components.UploadImage = Vue.defineAsyncComponent(() => import("./Upload/Image.js"));
} else if (this.tag == 'UploadDms' && !this._.components.UploadDms) {
+2 -1
View File
@@ -23,7 +23,8 @@ export default {
if (!Array.isArray(feedback))
feedback = [feedback];
const ts = Date.now();
this.feedback[valid ? 'success' : 'danger'] = feedback.map(msg => [msg, ts]);
this.feedback[valid ? 'success' : 'danger']
.push(...feedback.map(msg => [msg, ts]));
}
},
mounted() {
+9 -9
View File
@@ -295,7 +295,7 @@ export default {
showType_id: false,
showId: false,
showLastupdate: false
},
}
}
},
methods: {
@@ -464,7 +464,6 @@ export default {
});
},
initTinyMCE() {
const vm = this;
tinymce.init({
target: this.$refs.editor.$refs.input, //Important: not selector: to enable multiple import of component
@@ -502,15 +501,15 @@ export default {
const columnToShow = "show" + column.charAt(0).toUpperCase() + column.slice(1);
this.showVariables[columnToShow] = true;
});
},
}
},
created() {
this.initializeShowVariables();
this.getUid();
},
async mounted() {
if(this.showTinyMce){
this.initTinyMCE();
if (this.showTinyMce) {
await this.initTinyMCE();
}
},
watch: {
@@ -548,16 +547,17 @@ export default {
this.reload();
}
},
beforeDestroy() {
if(this.showTinyMce) {
this.editor.destroy();
beforeUnmount() {
if (this.editor && tinymce.get(this.editor.id)) {
tinymce.get(this.editor.id).remove();
this.editor = null;
}
},
template: `
<div class="core-notiz">
<div v-if="notizLayout=='classicFas'">
<core-filter-cmpt
ref="table"
:tabulator-options="tabulatorOptions"
@@ -17,21 +17,23 @@ export default {
},
template: `
<div class="stv-details-notizen h-100 pb-3">
<!-- mit factory als endpoint -->
<core-notiz
class="overflow-hidden"
:endpoint="endpoint"
ref="formc"
notiz-layout="popupModal"
type-id="person_id"
:id="modelValue.person_id"
show-document
show-tiny-mce
:visible-columns="['titel','text','verfasser','bearbeiter','dokumente']"
>
</core-notiz>
<!-- Test Version classicFas for enter with one click vs popupModal-->
<core-notiz
class="overflow-hidden"
:endpoint="endpoint"
ref="formc"
notiz-layout="popupModal"
type-id="person_id"
:id="modelValue.person_id"
show-document
show-tiny-mce
:visibleColumns="['titel','text','verfasser','bearbeiter','dokumente']"
@reload="$emit('update:suffix')"
>
</core-notiz>
<!--
---------------------------------------------------------------------------------------------
-------------------- DESCRIPTION FOR PARAMETER PROPS ----------------------------------------
@@ -146,14 +146,15 @@ export default {
this.addStudent({status_kurzbz: 'student', statusgrund_id});
},
addStudent(data) {
Promise
.allSettled(
this.prestudentIds.map(prestudent_id => this.$api.call(
ApiStvStatus.addStudent(prestudent_id, data),
{ errorHeader: prestudent_id }
))
)
.then(res => this.showFeedback(res, data.status_kurzbz));
this.$api.call(this.prestudentIds.map(prestudent_id => [
prestudent_id,
ApiStvStatus.addStudent(prestudent_id, data),
{ errorHeader: prestudent_id }
]))
.then(() => {
this.$emit('reloadTable');
this.$reloadList();
});
},
changeStatusToAbbrecher(statusgrund_id) {
this
@@ -247,31 +248,15 @@ export default {
},
changeStatus(data) {
data.currentSemester = this.currentSemester;
Promise
.allSettled(
this.prestudentIds.map(prestudent_id => this.$api.call(
ApiStvStatus.changeStatus(prestudent_id, data),
{ errorHeader: prestudent_id }
))
)
.then(res => this.showFeedback(res, data.status_kurzbz));
},
showFeedback(results, status_kurzbz) {
const countSuccess = results.filter(result => result.status == "fulfilled").length;
const countError = results.length - countSuccess;
//Feedback Success als infoalert
this.$fhcAlert.alertInfo(this.$p.t('ui', 'successNewStatus', {
countSuccess,
status: status_kurzbz,
countError
}));
if(results.length == 1 && countSuccess > 0){
this.$api.call(this.prestudentIds.map(prestudent_id => [
prestudent_id,
ApiStvStatus.changeStatus(prestudent_id, data)
]))
.then(() => {
this.$emit('reloadTable');
}
this.$reloadList();
}
this.$reloadList();
});
},
},
created() {
this.$api
@@ -359,4 +344,4 @@ export default {
</ul>
</div>
</div>`
};
};
@@ -193,7 +193,7 @@ export default {
// TODO(chris): move to fhcapi.factory
this.$refs.form
.send('api/frontend/v1/stv/student/add', data)
.post('api/frontend/v1/stv/student/add', data)
.then(result => {
this.$fhcAlert.alertSuccess('Gespeichert');
this.$refs.modal.hide();
@@ -213,7 +213,7 @@ export default {
},
template: `
<fhc-form ref="form" class="stv-list-new" @submit.prevent="send">
<bs-modal ref="modal" dialog-class="modal-lg modal-scrollable" @hidden-bs-modal="reset">
<bs-modal ref="modal" dialog-class="modal-lg modal-dialog-scrollable" @hidden-bs-modal="reset">
<template #title>
InteressentIn anlegen
</template>
@@ -1,15 +1,9 @@
import {CoreRESTClient} from '../../../RESTClient.js';
import PvTree from "../../../../../index.ci.php/public/js/components/primevue/tree/tree.esm.min.js";
import PvTreetable from "../../../../../index.ci.php/public/js/components/primevue/treetable/treetable.esm.min.js";
import PvColumn from "../../../../../index.ci.php/public/js/components/primevue/column/column.esm.min.js";
import ApiStvVerband from '../../../api/factory/stv/verband.js';
export default {
components: {
PvTree,
PvTreetable,
PvColumn
PvTreetable: primevue.treetable,
PvColumn: primevue.column
},
emits: [
'selectVerband'
@@ -31,14 +25,15 @@ export default {
selectedKey: [],
expandedKeys: {},
filters: {}, // TODO(chris): filter only 1st level?
favnodes: [],
favorites: {on: false, list: []}
}
},
computed: {
filteredNodes() {
// TODO(chris): what to display actually?
return this.favorites.on ? this.favnodes : this.nodes;
if (this.favorites.on)
return this.nodes.filter(node => this.favorites.list.includes(node.key));
return this.nodes;
}
},
watch: {
@@ -118,69 +113,49 @@ export default {
return cp;
},
async filterFav() {
if (!this.favorites.on && !this.favnodes.length && this.favorites.list.length) {
this.loading = true;
this.favnodes = await this.loadNodes(this.favorites.list);
}
this.favorites.on = !this.favorites.on;
this.$api
.call(this.endpoint.favorites.set(
JSON.stringify(this.favorites)
));
this.loading = false;
},
async loadNodes(links) {
let sortedInParents = links.reduce((o, link) => {
link = link + '';
let parent,
parts = link.split('/');
if (parts.length == 1) {
parent = '_';
} else {
parts.pop();
parent = parts.join('/');
}
if (!o[parent])
o[parent] = [link];
else
o[parent].push(link);
return o;
}, {});
let promises = [];
for (let parent in sortedInParents)
promises.push(
this.$api
.call(this.endpoint.get(parent == '_' ? '' : parent))
.then(res => res.data)
.then(res => res.filter(node => sortedInParents[parent].includes(node.link + '')))
);
// NOTE(chris): merge the resulting arrays and transform them to an associative one
let result = [].concat.apply([], await Promise.all(promises)).reduce((o, node) => {
o[node.link + ''] = this.mapResultToTreeData({...node, leaf: true, children: undefined});
return o;
}, {});
return links.map(link => result[link]);
))
.then(result => {
if (result.meta?.removed) {
this.favorites.list = this.favorites.list
.filter(fav => !result.meta.removed.includes(fav));
const items = result.meta.removed.map(
rem => this.nodes.find(
node => node.data.link == rem
).label
).join(',\n');
this.$fhcAlert.alertWarning(this.$p.t('stv/warn_removed_favs', { items }));
}
});
},
async markFav(key) {
let index = this.favorites.list.indexOf(key.data.link + '');
if (index != -1) {
if (this.favnodes.length)
this.favnodes = this.favnodes.filter(node => node.data.link != key.data.link);
this.favorites.list.splice(index, 1);
} else {
if (this.favnodes.length || this.favorites.on)
this.favnodes.push((await this.loadNodes([key.data.link])).pop());
this.favorites.list.push(key.data.link + '');
}
this.$api
.call(this.endpoint.favorites.set(
JSON.stringify(this.favorites)
));
))
.then(result => {
if (result.meta?.removed) {
this.favorites.list = this.favorites.list
.filter(fav => !result.meta.removed.includes(fav));
const items = "\n" + result.meta.removed.map(
rem => this.nodes.find(
node => node.data.link == rem
).label
).join(",\n");
this.$fhcAlert.alertWarning(this.$p.t('stv/warn_removed_favs', { items }));
}
});
},
unsetFavFocus(e) {
if (e.target.dataset?.linkFavAdd !== undefined) {
@@ -238,7 +213,10 @@ export default {
this.$api
.call(this.endpoint.get())
.then(result => {
this.nodes = result.data.map(this.mapResultToTreeData);
this.nodes = result.data.map(el => {
el.root = true;
return this.mapResultToTreeData(el);
});
this.setPreselection();
this.loading = false;
})
@@ -248,21 +226,12 @@ export default {
.call(this.endpoint.favorites.get())
.then(result => {
if (result.data) {
let f = JSON.parse(result.data);
if (f.on) {
this.loading = true;
this.favorites = f;
this.loadNodes(this.favorites.list).then(res => {
this.favnodes = res;
this.loading = false;
});
} else
this.favorites = f;
this.favorites = JSON.parse(result.data);
}
})
.catch(this.$fhcAlert.handleSystemError);
},
template: `
template: /* html */`
<div class="overflow-auto" tabindex="-1">
<pv-treetable
ref="tree"
@@ -278,39 +247,68 @@ export default {
@focusin="setFavFocus"
@focusout="unsetFavFocus"
:filters="filters"
>
<pv-column
field="name"
expander
class="text-break"
>
<pv-column field="name" expander>
<template #header>
<div class="text-right">
<div class="p-input-icon-left">
<i class="pi pi-search"></i>
<input type="text" v-model="filters['global']" class="form-control ps-5" placeholder="Search" />
<input
type="text"
v-model="filters['global']"
class="form-control ps-5"
placeholder="Search"
>
</div>
</div>
</template>
<template #body="{node}">
<span :data-tree-item-key="node.key" :title="node.data.studiengang_kz">
<template #body="{ node }">
<span
:data-tree-item-key="node.key"
:title="node.data.studiengang_kz"
>
{{node.data.name}}
</span>
</template>
</pv-column>
<pv-column field="fav" headerStyle="flex: 0 0 auto" style="flex: 0 0 auto">
<pv-column
field="fav"
class="flex-shrink-0 flex-grow-0"
header-class="flex-shrink-0 flex-grow-0"
>
<template #header>
<a href="#" @click.prevent="filterFav"><i :class="favorites.on ? 'fa-solid' : 'fa-regular'" class="fa-star"></i></a>
</template>
<template #body="{node, column}">
<a
v-if="favorites.on || favorites.list.length"
href="#"
@click.prevent="filterFav"
>
<i
:class="favorites.on ? 'fa-solid' : 'fa-regular'"
class="fa-star"
></i>
</a>
</template>
<template #body="{ node }">
<a
v-if="node.data.root"
href="#"
@click.prevent="markFav(node)"
@keydown.enter.stop.prevent="markFav(node)"
tabindex="-1"
data-link-fav-add
>
<i :class="favorites.list.includes(node.data.link + '') ? 'fa-solid' : 'fa-regular'" class="fa-star"></i>
@click.prevent="markFav(node)"
@keydown.enter.stop.prevent="markFav(node)"
>
<i
:class="favorites.list.includes(node.data.link + '') ? 'fa-solid' : 'fa-regular'"
class="fa-star"
></i>
</a>
</template>
</pv-column>
<pv-column field="studiengang_kz" class="d-none"></pv-column>
</pv-treetable>
</div>`
};
};
+67 -22
View File
@@ -40,7 +40,7 @@ export default {
currentTab() {
if (this.tabs[this.current])
return this.tabs[this.current];
return { component: 'div' };
},
value: {
@@ -67,9 +67,9 @@ export default {
}
},
methods: {
handleTabClick: function(index) {
handleTabClick: function (e) {
let keys = Object.keys(this.tabs);
this.change(keys[index]);
this.change(keys[e.index]);
},
change(key) {
this.$emit("change", key)
@@ -97,13 +97,20 @@ export default {
if (!item.component)
return console.error('Component missing for ' + key);
//making it reactive for showing headerSuffix
const value = Vue.reactive({
suffix: '',
showSuffix: item.showSuffix || false
});
tabs[key] = {
component: Vue.markRaw(Vue.defineAsyncComponent(() => import(item.component))),
title: Vue.computed(() => item.title || key),
config: item.config,
key,
value: {}
}
value,
suffixhelper: item.suffixhelper ?? null
};
}
if (Array.isArray(config))
@@ -118,36 +125,67 @@ export default {
this.current = Object.keys(tabs)[0];
}
this.tabs = tabs;
},
updateSuffix() {
this.getTabSuffix(this.currentTab);
},
async getTabSuffix(tab) {
if (!tab.value.showSuffix) {
return;
}
if (tab.suffixhelper !== null) {
const suffixhelper = await import(tab.suffixhelper);
const suffix = await suffixhelper.getSuffix(this.$api, this.modelValue);
tab.value.suffix = suffix;
} else {
tab.value.suffix = '';
}
},
getTabSuffixes() {
Object.entries(this.tabs).forEach(([key, item]) => this.getTabSuffix(item));
}
},
created() {
this.initConfig(this.config);
},
mounted() {
this.getTabSuffixes();
},
updated() {
this.getTabSuffixes();
},
template: `
<template v-if="useprimevue">
<tabview
:scrollable="true"
:lazy="true"
:activeIndex="calcActiveIndex"
@tab-click="handleTabClick"
>
<tabpanel
v-for="tab in tabs"
:key="tab.key"
:header="tab.title"
<tabview
:scrollable="true"
:lazy="true"
:activeIndex="calcActiveIndex"
@tab-click="handleTabClick"
>
<keep-alive>
<component :is="tab.component" v-model="value" :config="tab.config"></component>
</keep-alive>
</tabpanel>
</tabview>
<tabpanel
v-for="tab in tabs"
:key="tab.key"
:header="tab.title + ((tab.value.showSuffix && tab.value.suffix !== '') ? ' ' + tab.value.suffix : '')"
>
<keep-alive>
<component
:is="tab.component"
v-model="value"
:config="tab.config"
@update:suffix="updateSuffix($event)"
></component>
</keep-alive>
</tabpanel>
</tabview>
</template>
<template v-else="">
<div class="fhc-tabs d-flex" :class="vertical ? 'align-items-stretch gap-3' : (border ? 'flex-column' : 'flex-column gap-3')" v-if="Object.keys(tabs).length">
<div class="nav" :class="vertical ? 'nav-pills flex-column' : 'nav-tabs'">
<div
v-for="tab in tabs"
:key="tab.key"
@@ -157,15 +195,22 @@ export default {
:aria-current="tab.key == current ? 'page' : ''"
v-accessibility:tab.[vertical]
>
{{tab.title}}
{{tab.title}} <span v-if="tab.value.showSuffix && tab.value.suffix"> {{ tab.value.suffix }}</span>
</div>
</div>
<div :style="vertical ? '' : 'flex: 1 1 0%; height: 0%'" class="overflow-auto flex-grow-1" :class="vertical || !border ? '' : 'p-3 border-bottom border-start border-end'">
<keep-alive>
<component ref="current" :is="currentTab.component" v-model="value" :config="currentTab.config"></component>
<component
ref="current"
:is="currentTab.component"
v-model="value"
:config="currentTab.config"
@update:suffix="updateSuffix($event)"
></component>
</keep-alive>
</div>
</div>
</template>`
};
+49 -9
View File
@@ -95,7 +95,6 @@ export const CoreFilterCmpt = {
dataset: null,
datasetMetadata: null,
selectedFields: null,
notSelectedFields: null,
filterFields: null,
availableFilters: null,
@@ -107,6 +106,8 @@ export const CoreFilterCmpt = {
fetchCmptApiFunctionParams: null,
fetchCmptDataFetched: null,
fetchResult: null,
tabulator: null,
tableBuilt: false,
tabulatorHasSelector: false,
@@ -122,6 +123,11 @@ export const CoreFilterCmpt = {
};
},
computed: {
notSelectedFields() {
if (!this.fields || !this.selectedFields)
return null;
return this.fields.filter(x => this.selectedFields.indexOf(x) === -1)
},
filteredData() {
if (!this.dataset)
return [];
@@ -219,6 +225,32 @@ export const CoreFilterCmpt = {
await this.$p.loadCategory('ui');
placeholder = this.$p.t('ui/keineDatenVorhanden');
}
if (!this.tableOnly) {
// prefetch data to get fields & selectedFields for filteredColumns & filteredData
await new Promise(resolve => {
const filterId = window.location.hash ? window.location.hash.slice(1) : null;
const resolvePromiseFunc = data => {
this.setRenderData(data);
resolve();
};
// get the filter data
if (filterId === null)
this.startFetchCmpt(
wsParams => this.$api.call(ApiFilter.getFilter(wsParams)),
null,
resolvePromiseFunc
);
else
this.startFetchCmpt(
wsParams => this.$api.call(ApiFilter.getFilterById(wsParams)),
{ filterId },
resolvePromiseFunc
);
});
}
// Define a default tabulator options in case it was not provided
let tabulatorOptions = {...{
layout: "fitDataStretchFrozen",
@@ -240,6 +272,11 @@ export const CoreFilterCmpt = {
if (!this.tableOnly) {
tabulatorOptions.data = this.filteredData;
tabulatorOptions.columns = this.filteredColumns;
} else {
tabulatorOptions.columns.forEach(col => {
if (col.visible === undefined)
col.visible = true;
});
}
if (tabulatorOptions.selectable || (tabulatorOptions.columns && tabulatorOptions.columns.filter(el => el.formatter == 'rowSelection').length))
@@ -359,18 +396,14 @@ export const CoreFilterCmpt = {
this.render
);
},
/**
*
*/
render(response) {
let data = response;
setRenderData(data) {
this.fetchResult = data;
this.filterName = data.filterName;
this.dataset = data.dataset;
this.datasetMetadata = data.datasetMetadata;
this.fields = data.fields;
this.selectedFields = data.selectedFields;
this.notSelectedFields = this.fields.filter(x => this.selectedFields.indexOf(x) === -1);
this.filterFields = [];
for (let i = 0; i < data.datasetMetadata.length; i++)
@@ -387,6 +420,14 @@ export const CoreFilterCmpt = {
}
}
}
},
/**
*
*/
render(response) {
let data = response;
this.setRenderData(data);
// If the side menu is active
if (this.sideMenu === true)
@@ -627,11 +668,10 @@ export const CoreFilterCmpt = {
this.$emit('uuidDefined', this.uuid)
},
mounted() {
this.initTabulator().then(() => {
if (!this.tableOnly) {
this.selectedFilter = window.location.hash ? window.location.hash.slice(1) : null;
this.getFilter(); // get the filter data
this.render(this.fetchResult);
}
});
@@ -0,0 +1,8 @@
import ApiNotizPerson from '../../../../../api/factory/notiz/person.js';
export async function getSuffix(api, modelValue) {
const response = await api
.call(ApiNotizPerson.getCountNotes(modelValue.person_id));
const suffix = '(' + response.data + ')';
return suffix;
}
-1
View File
@@ -44,7 +44,6 @@ $(document).ready(function ()
"nachname" : $('#nachname_input').val(),
"titelpost" : $('#titelpost_input').val(),
"gebdatum" : $('#gebdatum_input').val(),
"svnr" : $('#svnr_input').val(),
"buergerschaft" : $('#buergerschaft').val(),
"geschlecht" : $('#geschlecht').val(),
"gebnation" : $('#gebnation').val(),
+75 -1
View File
@@ -42,12 +42,15 @@ export default {
}
function _clean_return_value(response) {
if (typeof response.data === 'string' || response.data instanceof String)
return _clean_return_value({ data: response });
const result = response.data;
delete response.data;
if (!result)
return {meta: {response}, data: null};
if (!result.meta)
result.meta = {response};
result.meta = { response };
else
result.meta.response = response;
return result;
@@ -161,6 +164,77 @@ export default {
return fhcApiAxios.post(uri, data, config);
},
call(factory, configoverwrite, form) {
if (Array.isArray(factory)) {
const $fhcAlert = app.config.globalProperties.$fhcAlert;
const $api = app.config.globalProperties.$api;
Promise
.allSettled(factory.map((config, index) => {
if (Array.isArray(config))
return $api.call(config[1], {
errorHeader: config[0],
errorHandling: false
});
else
return $api.call(config, {
errorHeader: '#' + index,
errorHandling: false
});
}))
.then(res => {
// TODO(chris): obey form & configoverwrite
let messagesError = [];
let messagesSuccessful = [];
res.forEach(result => {
if (result.status === 'fulfilled') {
//console.log(JSON.parse(result.value.data));
const successTitle = "<dt>" + result.value.data + "</dt>";
messagesSuccessful.push(successTitle + "ok");
} else {
const errorTitle = "<dt>" + result.reason.config.errorHeader + "</dt>";
const errorMsg = JSON.parse(result.reason.request.response);
const fullMessage = errorMsg.errors.map(error => {
if (error.type == 'validation') {
// TODO(chris): do we want the keys?
return '<dd>' + Object.values(error.messages).join("</dd><dd>") + '</dd>';
}
// TODO(chris): other types
if (error.message)
return '<dd>' + error.message + '</dd>';
if (error.messages)
return '<dd>' + error.messages.join("\n") + '</dd>';
// TODO(chris): what to do here
return '<dd>' + "Generic Error" + '</dd>'; // TODO(chris): translate
}).join("\n");
messagesError.push(errorTitle + fullMessage);
}
});
if (messagesError.length)
{
const test = document.createElement('b');
$fhcAlert.alertDefault(
'error',
messagesError.length + " Fehler", // TODO(chris): translate
'<dl>' + messagesError.join("") + '</dl>',
true,
true
);
}
if (messagesSuccessful.length)
{
const test = document.createElement('b');
$fhcAlert.alertDefault(
'info',
'Feedback',
messagesSuccessful.length + " erfolgreiche Statusänderung(en) durchgeführt", // TODO(chris): translate
false,
true
);
}
});
}
let {method, url, params, config} = factory;
if (configoverwrite !== undefined) {
config = configoverwrite;
+14 -5
View File
@@ -140,7 +140,16 @@ const helperApp = Vue.createApp({
}
},
template: /* html */`
<pv-toast ref="toast" class="fhc-alert" :base-z-index="99999"></pv-toast>
<pv-toast ref="toast" class="fhc-alert" :base-z-index="99999">
<template #message="{ message }">
<!--span :class="slotProps.iconClass"></span-->
<div class="p-toast-message-text">
<span class="p-toast-summary">{{ message.summary }}</span>
<div v-if="message.detail && message.html" class="p-toast-detail" v-html="message.detail"></div>
<div v-else-if="message.detail" class="p-toast-detail">{{ message.detail }}</div>
</div>
</template>
</pv-toast>
<pv-toast ref="alert" class="fhc-alert" :base-z-index="99999" position="center">
<template #message="slotProps">
<i class="fa fa-circle-exclamation fa-2xl mt-3"></i>
@@ -263,18 +272,18 @@ export default {
});
});
},
alertDefault(severity, title, message, sticky = false) {
let options = { severity: severity, summary: title, detail: message};
alertDefault(severity, title, message, sticky = false, html = false) {
let options = { severity: severity, summary: title, detail: message, html };
if (!sticky)
options.life = 3000;
helperAppInstance.$refs.toast.add(options);
},
alertMultiple(messageArray, severity = 'info', title = 'Info', sticky = false){
alertMultiple(messageArray, severity = 'info', title = 'Info', sticky = false, html = false){
// Check, if array has only string values
if (messageArray.every(message => typeof message === 'string')) {
messageArray.forEach(message => this.alertDefault(severity, title, message, sticky));
messageArray.forEach(message => this.alertDefault(severity, title, message, sticky, html));
return true;
}
return false;
@@ -1,5 +1,6 @@
<?php
$raum_contentmittitel_xslt_xhtml= <<<EOD
<xsl:stylesheet version="1.0" xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
@@ -8,27 +9,56 @@ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<head>
<title><xsl:value-of select="titel" /></title>
<link rel="stylesheet" href="../skin/style.css.php" type="text/css" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/tabulator/5.0.7/css/tabulator.min.css" rel="stylesheet" />
<script type="text/javascript" src="https://c3p0.ma0594.technikum-wien.at/fh-core/vendor/olifolkerd/tabulator5/dist/js/tabulator.min.js?2019102903"></script>
<link rel="stylesheet" href="../skin/jquery.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="../skin/jquery-ui-1.9.2.custom.min.css" />
<script type="text/javascript" src="../vendor/jquery/jquery1/jquery-1.12.4.min.js"></script>
<script type="text/javascript" src="../vendor/christianbach/tablesorter/jquery.tablesorter.min.js"></script>
<script type="text/javascript" src="../vendor/components/jqueryui/jquery-ui.min.js"></script>
<script type="text/javascript" src="../include/js/jquery.ui.datepicker.translation.js"></script>
<script type="text/javascript" src="../vendor/jquery/sizzle/sizzle.js"></script>
<link rel="stylesheet" href="../skin/tablesort.css" type="text/css"/>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function()
{
let tables = document.getElementsByClassName("tablesorter");
for(table of tables){
new Tabulator(table, {
layout:"fitDataFill",
autoResize:true,
resizableRows:true,
columnDefaults:{
formatter:"html",
resizable:true,
}
})
}
});
$(document).ready(function()
{
$(".tablesorter").each(function()
{
var col=0;
var sort=0;
var no_sort=1;
var classes = $(this).attr("class");
var class_arr = classes.split(" ");
var headersobj={};
for(i in class_arr)
{
if(class_arr[i].indexOf("tablesorter_col_")!=-1)
{
col = class_arr[i].substr(16);
}
if(class_arr[i].indexOf("tablesorter_sort_")!=-1)
{
sort = class_arr[i].substr(17);
}
if(class_arr[i].indexOf("tablesorter_no_sort_")!=-1)
{
no_sort = class_arr[i].substr(20);
headersobj[no_sort]={sorter:false};
}
}
$(this).tablesorter(
{
sortList: [[col,sort]],
widgets: ["zebra"],
headers: headersobj
});
});
});
</script>
</head>
<body>
<h1><xsl:value-of select="titel" /></h1>
+103
View File
@@ -1456,6 +1456,109 @@ $filters = array(
',
'oe_kurzbz' => null,
),
array(
'app' => 'personalverwaltung',
'dataset_name' => 'schluesselverwaltung',
'filter_kurzbz' => 'ma4schluesselverwaltung',
'description' => '{MA Schluesselverwaltung}',
'sort' => 1,
'default_filter' => true,
'filter' => '
{
"name": "MA Schlüsselverwaltung",
"columns": [
{"name": "UID"},
{"name": "PersonId"},
{"name": "Vorname"},
{"name": "Nachname"},
{"name": "EMail"},
{"name": "Unternehmen"},
{"name": "Vertragsart"},
{"name": "DV_von"},
{"name": "DV_bis"},
{"name": "Wochenstunden"},
{"name": "WS_von"},
{"name": "WS_bis"},
{"name": "Standardkostenstelle"},
{"name": "DV_status"}
],
"filters": [
{
"name": "DV_status",
"option": "",
"operation": "nequal",
"condition": "beendet"
}
]
}
',
'oe_kurzbz' => null,
),
array(
'app' => 'personalverwaltung',
'dataset_name' => 'schluesselverwaltung',
'filter_kurzbz' => 'ma4schluesselverwaltung_beendet',
'description' => '{MA Schluesselverwaltung (DV beendet)}',
'sort' => 2,
'default_filter' => false,
'filter' => '
{
"name": "MA Schlüsselverwaltung (DV beendet)",
"columns": [
{"name": "UID"},
{"name": "PersonId"},
{"name": "Vorname"},
{"name": "Nachname"},
{"name": "EMail"},
{"name": "Unternehmen"},
{"name": "Vertragsart"},
{"name": "DV_von"},
{"name": "DV_bis"},
{"name": "Wochenstunden"},
{"name": "WS_von"},
{"name": "WS_bis"},
{"name": "Standardkostenstelle"},
{"name": "DV_status"}
],
"filters": [
{
"name": "DV_status",
"option": "",
"operation": "equal",
"condition": "beendet"
}
]
}
',
'oe_kurzbz' => null,
),
array(
'app' => 'personalverwaltung',
'dataset_name' => 'kontaktdatenverwaltung',
'filter_kurzbz' => 'ma4kontaktdaten',
'description' => '{MA Kontaktdatenverwaltung}',
'sort' => 1,
'default_filter' => true,
'filter' => '
{
"name": "MA Kontaktdatenverwaltung",
"columns": [
{"name": "UID"},
{"name": "PersonId"},
{"name": "Vorname"},
{"name": "Nachname"},
{"name": "Unternehmen"},
{"name": "Vertragsart"},
{"name": "DV_von"},
{"name": "DV_bis"},
{"name": "Disziplinaere_Zuordnung"},
{"name": "DV_status"}
],
"filters": []
}',
'oe_kurzbz' => null,
),
);
// Loop through the filters array
+727 -40
View File
@@ -30281,7 +30281,6 @@ array(
)
)
),
//ProfilUpdate Phrasen ende
array(
@@ -30627,6 +30626,46 @@ array(
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'entschuldigtLegendeBlau',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Student ist am gewählten Datum bestätigt entschuldigt.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Student is confirmed excused on the selected date.',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'entschuldigtLegendeTuerkis',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Student hat eine offene Entschuldigung am gewählten Datum.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Student has an open excuse on the selected date.',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
@@ -30887,6 +30926,26 @@ array(
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'kontrolleOhneQR',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Anwesenheiten ohne QR-Code einfügen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Insert attendances without QR-Code',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
@@ -30947,6 +31006,46 @@ array(
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'kontrolle',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Anwesenheitskontrolle',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'attendance check',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'offen',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Offen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Open',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
@@ -31010,18 +31109,58 @@ array(
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'entschuldigungAutoEmailBetreff',
'phrase' => 'entFullEmailBetreff',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Entschuldigung zur Befreiung der Anwesenheitspflicht: Neues Dokument wurde hochgeladen.',
'text' => 'Neue Entschuldigung zur Befreiung der Anwesenheitspflicht: Neues Dokument wurde hochgeladen.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Excuse note for digital attendances - a new document has been uploaded.',
'text' => 'New Excuse note for digital attendances - a new document has been uploaded.',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'entNewEmailBetreff',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Neue Entschuldigung zur Befreiung der Anwesenheitspflicht: Dokument wird nachgereicht.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'New Excuse note for digital attendances - Document will be submitted later',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'entEditEmailBetreff',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Entschuldigung zur Befreiung der Anwesenheitspflicht: Dokument wurde eingereicht.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Excuse note for digital attendances - Document has been submitted',
'description' => '',
'insertvon' => 'system'
)
@@ -32310,18 +32449,78 @@ array(
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'studentConfig',
'phrase' => 'errorCodeTooOld',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Studenten auswählen.',
'text' => 'Der Zugangscode ist zeitlich abgelaufen.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Configure student profile.',
'text' => 'The access code has expired.',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'profil',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Profil',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'profile',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'admin',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Entschuldigungsmanagement',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'excuse note management',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'allowed',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Aktuell prüfbar',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'allowed to test',
'description' => '',
'insertvon' => 'system'
)
@@ -32367,6 +32566,26 @@ array(
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'termineV2',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Unterricht laut LV-Plan',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Lesson as per Timetable',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
@@ -32375,7 +32594,7 @@ array(
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Termine laut Stundenplan',
'text' => 'Unterricht laut LV-Plan',
'description' => '',
'insertvon' => 'system'
),
@@ -32470,18 +32689,18 @@ array(
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'noStudentsFound',
'phrase' => 'noStudentsFoundV2',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Keine zugeteilten Studenten gefunden!',
'text' => 'Keine zugeteilten Studenten für Mitarbeiter {0} in dem gewählten LV-Teil {1} gefunden!',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'No assigned students found!',
'text' => 'No assigned students for employee {0} in the selected teaching unit {1} found!',
'description' => '',
'insertvon' => 'system'
)
@@ -32490,7 +32709,7 @@ array(
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'kontrolldatum',
'phrase' => 'kontrolldatumV2',
'insertvon' => 'system',
'phrases' => array(
array(
@@ -32501,7 +32720,27 @@ array(
),
array(
'sprache' => 'English',
'text' => 'Attendance Check Date',
'text' => 'Check Date',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'kontrollen',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Kontrollen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Attendance Checks',
'description' => '',
'insertvon' => 'system'
)
@@ -32810,12 +33049,12 @@ array(
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'zeitNichtAusStundenplanBeginn',
'phrase' => 'zeitNichtAusStundenplanBeginnV2',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Unterrichtbeginn entspricht keinem Unterrichtstermin laut Stundenplan.',
'text' => 'Unterrichtbeginn entspricht keinem Unterrichtstermin laut LV-Plan.',
'description' => '',
'insertvon' => 'system'
),
@@ -32830,12 +33069,12 @@ array(
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'zeitNichtAusStundenplanEnde',
'phrase' => 'zeitNichtAusStundenplanEndeV2',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Unterrichtende entspricht keinem Unterrichtstermin laut Stundenplan.',
'text' => 'Unterrichtende entspricht keinem Unterrichtstermin laut LV-Plan.',
'description' => '',
'insertvon' => 'system'
),
@@ -32850,12 +33089,12 @@ array(
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'datumNichtAusStundenplan',
'phrase' => 'datumNichtAusStundenplanV2',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Datum entspricht keinem Stundenplan Termin.',
'text' => 'Datum entspricht keinem LV-Plan Termin.',
'description' => '',
'insertvon' => 'system'
),
@@ -32867,6 +33106,66 @@ array(
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'kontrolleTimeOverlap',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Kontrollzeiten überlappen mit Kontrolle von {0} bis {1}.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Times overlap with attendance check from {0} to {1}.',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'keineKontrollenAnDatumFallback',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Keine Kontrollen an {0} gefunden, es werden alle Kontrollen angezeigt.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'No attendance checks found on {0}, all attendance checks are being shown.',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'noLePreselectTermineTooOld',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Keine intelligente LV-Teil Vorauswahl möglich, da sämtliche Termine außerhalb des erlaubten Kontrollzeitraums liegen. Bitte wählen Sie sorgfältig den gewünschten LV-Teil aus.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'No intelligent pre-selection of teaching unit is possible, as all dates fall outside the permitted control period. Please carefully select the desired teaching unit.',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
@@ -32922,22 +33221,18 @@ array(
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'tooltipAssistenz',
'phrase' => 'tooltipAssistenzV2',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Im Entschuldigungsmanagement können Sie als Studiengangsassistenz beziehungsweise als Administrator die von Studenten hochgeladenen Entschuldigungsdokumente überprüfen und den Status entsprechend vergeben.
Bitte beachten Sie dass nur Entschuldigungen INNERHALB des angegebenen Zeitraumes angezeigt werden. Sollten Sie nach einer lang wirken Entschuldigung suchen, müssen Sie die Zeitspanne entsprechend weit setzen.',
'text' => 'Im Entschuldigungsmanagement können Sie als Studiengangsassistenz beziehungsweise als Administrator die von Studenten hochgeladenen Entschuldigungsdokumente überprüfen und den Status entsprechend vergeben.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'In the excuse management, you as a course assistant or administrator can check the excuse documents uploaded by students and assign the status accordingly.
Please note that only excuses WITHIN the specified time period are displayed. If you are looking for a long-lasting excuse, you must set the time period accordingly.',
'text' => 'In the excuse management, you as a course assistant or administrator can check the excuse documents uploaded by students and assign the status accordingly.',
'description' => '',
'insertvon' => 'system'
)
@@ -32970,16 +33265,16 @@ array(
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'tooltipLektorStartKontrolle',
'phrase' => 'tooltipLektorStartKontrolleV4',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Um eine Anwesenheitskontrolle für Ihre ausgewählte Unterrichtsgruppe durchzuführen, wählen Sie bitte einen Termin aus dem Stundenplan aus oder geben händisch die gewünschte Gültigkeitkeitsdauer der Kontrolle an.
'text' => 'Um eine Anwesenheitskontrolle für Ihre ausgewählte Unterrichtsgruppe durchzuführen, wählen Sie bitte einen Termin aus dem LV-Plan aus oder geben händisch die gewünschte Gültigkeitkeitsdauer der Kontrolle an.
Die Gültigkeitsdauer bestimmt die Gewichtung der Anwesenheit in Relation zum Gesamtausmaß, sie können diese aber nach eigenem Ermessen anpassen und müssen sich nicht streng an die Termine im Stundenplan halten.
Die Gültigkeitsdauer bestimmt die Gewichtung der Anwesenheit in Relation zum Gesamtausmaß, sie können diese aber nach eigenem Ermessen anpassen und müssen sich nicht streng an die Termine im LV-Plan halten.
Sie können pro Datum und Unterrichtsgruppe eine Anwesenheitskontrolle pro Tag eröffnen, welche jedoch beliebig oft aufgerufen und von Studenten eingecheckt werden kann. Es gelten dabei ihre zuletzt eingetragenen Zeiten. Ein Student muss nur einmal am Tag pro Gruppe einchecken um als anwesend registriert zu sein, egal wie oft Sie die Kontrolle starten.',
Sie können pro Datum und Unterrichtsgruppe mehrere Anwesenheitskontrollen am Tag durchführen, solange sich diese nicht in Ihren Zeiten überschneiden und eine Mindestlänge von {0} Minuten beträgt.',
'description' => '',
'insertvon' => 'system'
),
@@ -32989,7 +33284,7 @@ array(
The validity period determines the weighting of attendance in relation to the overall extent, but you can adjust this at your own discretion and do not have to stick strictly to the dates in the timetable.
You can open one attendance check per day for each date and class group, which can be called up and checked in by students as often as you like. The times they last entered apply. A student only has to check in once a day per group to be registered as present, regardless of how often you start the check.',
You can conduct multiple attendance checks per day per date and lesson group, as long as they do not overlap in your times and are at least {0} minutes long.',
'description' => '',
'insertvon' => 'system'
)
@@ -33066,18 +33361,38 @@ array(
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'anwTimeline',
'phrase' => 'anwTimelineV2',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Digitale Anwesenheiten Timeline',
'text' => 'Digitale Anwesenheiten Timeline EXPERIMENTELL',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Digital Attendances Timeline',
'text' => 'Digital Attendances Timeline EXPERIMENTAL',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'studentenInLVTeil',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Studenten in LV-Teil',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Students in teaching unit',
'description' => '',
'insertvon' => 'system'
)
@@ -33103,6 +33418,26 @@ array(
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'file',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Dokument',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Document',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
@@ -33206,12 +33541,12 @@ array(
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'termineAusStundenplan',
'phrase' => 'termineAusStundenplanV2',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Unterricht Termine laut Stundenplan',
'text' => 'Unterricht Termine laut LV-Plan',
'description' => '',
'insertvon' => 'system'
),
@@ -33226,12 +33561,12 @@ array(
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'tooltipUnterrichtZeitCustom',
'phrase' => 'tooltipUnterrichtZeitCustomV2',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Unterrichtszeiten werden aus dem Stundenplan geladen, überschreiben Sie diese nur falls Ihre tatsächliche Unterrichtszeiten davon abweichen!',
'text' => 'Unterrichtszeiten werden aus dem LV-Plan geladen, überschreiben Sie diese nur falls Ihre tatsächliche Unterrichtszeiten davon abweichen!',
'description' => '',
'insertvon' => 'system'
),
@@ -33246,12 +33581,12 @@ array(
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'tooltipUnterrichtDatumCustom',
'phrase' => 'tooltipUnterrichtDatumCustomV2',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Unterrichtsdaten werden aus dem Stundenplan geladen, überschreiben Sie dieses nur falls Ihr tatsächliches Unterrichtsdatum abweicht!',
'text' => 'Unterrichtsdaten werden aus dem LV-Plan geladen, überschreiben Sie dieses nur falls Ihr tatsächliches Unterrichtsdatum abweicht!',
'description' => '',
'insertvon' => 'system'
),
@@ -33363,6 +33698,338 @@ array(
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'kontrolleDatumOutOfRange',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Datum liegt außerhalb der erlaubten Kontrollspanne!',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Date is outside the permitted control range!',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'alertBetreuungSelected',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Der ausgewählte LV-Teil hat die Lehrform Betreuung! Bitte überprüfen sie die korrekte Auswahl des LV-Teils um fehlerhafte Kontrollen zu vermeiden!',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'The selected course component is taught in a supervised format! Please check that you have selected the correct course component to avoid incorrect assessments!',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'editEntschuldigung',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Entschuldigung bearbeiten',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Edit Excuse note',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'anwUserEntry',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Anwesenheitseintrag',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Attendance Entry',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'highlightsettings',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Datumsmarkierung',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Date Highlighting',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'editAnwKontrolle',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Anwesenheitskontrolle bearbeiten',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Edit Attendance Checks',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'tooltipAnwTimeline',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Die "Digitale Anwesenheiten Timeline" ist ein experimentelles feature, welches eine zeitliche Visualisierung von Entschuldigungszeiträumen und Kontrollzeiträumen im Kontext eines Studenten anzeigt.
Wenn Sie auf eine aufgelistete Entschuldigung oder Kontrolle klicken, versucht die Timeline diese zu finden, falls diese im angegebenen Zeitraum liegt, welcher standardmäßig das gesamte aktuelle Jahr beträgt. Sie können diese Grenzen manuell anpassen.
Wenn man innerhalb der Timeline scrollt, ändert sich der visuelle Abstand zwischen einzelnen Tagen.
Bei Klick auf eine gerenderte Datumsreichweite in der Timeline, listet sich oben rechts eine Liste von zugehörigen Attributen auf, welche Administratoren und Entwicklern in Fehlerfällen helfen sollen den Zustand der digitalen Amwesenheiten im Kontext eines Studierenden nachzuvollziehen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'The "Digital Attendance Timeline" is an experimental feature that displays a temporal visualization of excuse periods and check-in periods in the context of a student.
When you click on a listed excuse or check-in period, the timeline attempts to find it if it falls within the specified period, which by default is the entire current year. You can adjust these boundaries manually.
Scrolling within the timeline changes the visual spacing between individual days.
Clicking on a rendered date range in the timeline displays a list of associated attributes in the upper right corner. These attributes are intended to help administrators and developers understand the status of digital attendance in the context of a student in case of errors.',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'kontrolleRestart',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Kontrolle wiederholen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Restart attendance check',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'tooltipLegende',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Status Legende für das Digitales Anwesenheiten und Entschuldigungsmanagement anzeigen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Show status legend for the digital attendance and excuse note management',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'tooltipCsv',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Tabelle als CSV Datei exportiern',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Export table as CSV file',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'tooltipEdit',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Anwesenheitskontrollen bearbeiten',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Edit attendance checks',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'tooltipSaveChanges',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Manuell veränderte Anwesenheiten speichern',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Save manually edited attendance entries',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'tooltipRestartKontrolle',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Bestehende Anwesenheitskontrolle neu starten. Studierende, welche bereits gültig registriert sind, gelten weiterhin als anwesend!',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Restart existing attendance check. Students who are already validly registered will continue to be considered present!',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'tooltipDeleteKontrolle',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Anwesenheitskontrolle löschen. Die dazugehörigen Statuseinträge der Studierenden werden auch gelöscht!',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Delete attendance checks. The corresponding student status entries will also be deleted!',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'tooltipEditKontrollzeiten',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Zeitgrenzen einer Kontrolle bearbeiten',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Edit time limits of an attendance check',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'anwesenheit',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Anwesenheit',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Attendance',
'description' => '',
'insertvon' => 'system'
)
)
),
//
// DIGITALE ANWESENHEITEN PHRASEN END
//
@@ -37553,6 +38220,26 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'warn_removed_favs',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Zu viele Favoriten! Die folgenden Einträge wurden entfernt: {items}',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Too many favorites! The following entries were removed: {items}',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'stv',
+2 -1
View File
@@ -309,7 +309,8 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0"
<text:p text:style-name="P4">(nz) ... nicht zugelassen</text:p>
<text:p text:style-name="P4">(ma) ... MitarbeiterIn</text:p>
<text:p text:style-name="P4">(a.o.) ... Außerordentliche/r HörerIn</text:p>
<text:p text:style-name="P4">(d.d.) ... Double Degree Program</text:p>
<text:p text:style-name="P4">(d.d.i) ... Double Degree Incoming Program</text:p>
<text:p text:style-name="P4">(d.d.o) ... Double Degree Outgoing Program</text:p>
<text:p text:style-name="P4"/>
<text:p text:style-name="P5">
<xsl:choose>