mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-10-12 15:04:04 +00:00
Compare commits
70
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90bce8d3d5 | ||
|
|
364b506220 | ||
|
|
c6b1d518cf | ||
|
|
b2213bff62 | ||
|
|
411d2192cb | ||
|
|
bae9d6d9a0 | ||
|
|
43d6a882ce | ||
|
|
7f3b4100ab | ||
|
|
9f54ecce54 | ||
|
|
7af0f4a478 | ||
|
|
0f843db33d | ||
|
|
3e59648d5b | ||
|
|
5923991848 | ||
|
|
55a6ec9d0d | ||
|
|
78505589c8 | ||
|
|
0e985113ec | ||
|
|
8d9113d5c8 | ||
|
|
7ce81ad4bd | ||
|
|
ea56ec8daa | ||
|
|
bf5ee2f64b | ||
|
|
55d6d90fa6 | ||
|
|
6adc55a843 | ||
|
|
52c1fba17b | ||
|
|
5e15d4b219 | ||
|
|
00954f680b | ||
|
|
36a302f20f | ||
|
|
92d27fc242 | ||
|
|
558963cd74 | ||
|
|
9a592047a0 | ||
|
|
e6947a3246 | ||
|
|
5cd0897348 | ||
|
|
00f07ba6f0 | ||
|
|
d8355ba3f5 | ||
|
|
afb8011347 | ||
|
|
d85a3cb08f | ||
|
|
15beaa9be8 | ||
|
|
574057da88 | ||
|
|
c81b5338de | ||
|
|
c433ff5c3a | ||
|
|
a5797a0bde | ||
|
|
37d5f2da5d | ||
|
|
27c39cfdca | ||
|
|
d66fe72cc9 | ||
|
|
59ac56374e | ||
|
|
a397460e0e | ||
|
|
108f91ea1a | ||
|
|
dc5a846c10 | ||
|
|
06895510e0 | ||
|
|
83b06b6c50 | ||
|
|
bd99f3f927 | ||
|
|
eeb1529b64 | ||
|
|
98c3707802 | ||
|
|
0d5c898106 | ||
|
|
e5c8807f17 | ||
|
|
2f86a1b017 | ||
|
|
75ddbdf7c1 | ||
|
|
d824334538 | ||
|
|
13515b2522 | ||
|
|
0a46bf52dd | ||
|
|
1afc4c9a29 | ||
|
|
96b4210d21 | ||
|
|
85fcecdcf6 | ||
|
|
55dc2b26d2 | ||
|
|
9c7a85826b | ||
|
|
e876b9e4ab | ||
|
|
c5c29df6cc | ||
|
|
9c7e98f1cb | ||
|
|
c34ffedb42 | ||
|
|
b5382b1bdf | ||
|
|
519cbc7601 |
@@ -68,6 +68,11 @@ $route['Cis/OtherLvPlan/.*'] = 'Cis/OtherLvPlan/index/$1';
|
||||
//Route for LV Plan Stg/Semester/Verband/Gruppe
|
||||
$route['Cis/StgOrgLvPlan/.*'] = 'Cis/StgOrgLvPlan/index/$1';
|
||||
|
||||
//Route for Zeitsperrenma
|
||||
$route['Cis/Zeitsperrenma/.*'] = 'Cis/Zeitsperrenma/index/$1';
|
||||
//Route für Zeitsperren
|
||||
$route['Cis/Zeitsperren/.*'] = 'Cis/Zeitsperren/index/$1';
|
||||
|
||||
$route['Abgabetool/Assistenz'] = 'Cis/Abgabetool/Assistenz';
|
||||
$route['Abgabetool/Assistenz/(:any)'] = 'Cis/Abgabetool/Assistenz/$1';
|
||||
$route['Abgabetool/Mitarbeiter'] = 'Cis/Abgabetool/Mitarbeiter';
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class Zeitsperren extends Auth_Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'index' => ['basis/cis:r'],
|
||||
]);
|
||||
|
||||
// Load Libraries
|
||||
$this->load->library('VariableLib', ['uid' => getAuthUID()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* index loads the view Zeitsperren
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$viewData = array(
|
||||
'uid'=>getAuthUID(),
|
||||
);
|
||||
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'zeitsperren']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Zeitsperrenma extends Auth_Controller
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'index' => ['basis/cis:r']
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'Zeitsperrenma']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class MaZeitsperren extends FHCAPI_Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'getAllActiveZeitsperren' => ['basis/mitarbeiter:r', 'admin:r', 'assistenz:r'],
|
||||
'getAllZeitsperrenFixeMa' => ['basis/mitarbeiter:r', 'admin:r', 'assistenz:r'],
|
||||
'getAllZeitsperrenLector' => ['basis/mitarbeiter:r', 'admin:r', 'assistenz:r'],
|
||||
'getAllZeitsperrenOes' => ['basis/mitarbeiter:r', 'admin:r', 'assistenz:r'],
|
||||
'getZeitsperrenAss' => ['basis/mitarbeiter:r', 'admin:r', 'assistenz:r'],
|
||||
'getStgLectors' => self::PERM_LOGGED,
|
||||
'loadZeitsperrenLectorStg' => ['basis/mitarbeiter:r', 'admin:r', 'assistenz:r'],
|
||||
'loadZeitsperrenMa' => ['basis/mitarbeiter:r', 'admin:r', 'assistenz:r'],
|
||||
'getDetailsMa' => self::PERM_LOGGED
|
||||
]);
|
||||
|
||||
// Load Libraries
|
||||
$this->load->library('VariableLib', ['uid' => getAuthUID()]);
|
||||
$this->load->library('form_validation');
|
||||
|
||||
// Load language phrases
|
||||
$this->loadPhrases([
|
||||
'ui',
|
||||
'person',
|
||||
'zeitsperren'
|
||||
]);
|
||||
|
||||
// Load models
|
||||
$this->load->model('ressource/Zeitsperre_model', 'ZeitsperreModel');
|
||||
}
|
||||
|
||||
//only user with zeitsperren
|
||||
public function getAllActiveZeitsperren($days)
|
||||
{
|
||||
$result = $this->ZeitsperreModel->getZeitsperrenForNextDays($days);
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
//TODO: check query: more results after join with hr-table
|
||||
//all fixe Ma
|
||||
public function getAllZeitsperrenFixeMa($days)
|
||||
{
|
||||
$von = date('Y-m-d');
|
||||
$bis = date('Y-m-d', strtotime("+{$days} days"));
|
||||
$result = $this->ZeitsperreModel->getMitarbeiterWithZeitsperren($von, $bis, true, false, null, false);
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function getAllZeitsperrenLector($days)
|
||||
{
|
||||
$von = date('Y-m-d');
|
||||
$bis = date('Y-m-d', strtotime("+{$days} days"));
|
||||
$result = $this->ZeitsperreModel->getMitarbeiterWithZeitsperren($von, $bis, false, true, null, false);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function getZeitsperrenAss($days)
|
||||
{
|
||||
$von = date('Y-m-d');
|
||||
$bis = date('Y-m-d', strtotime("+{$days} days"));
|
||||
$result = $this->ZeitsperreModel->getMitarbeiterWithZeitsperren($von, $bis, false, false, null, true);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function getAllZeitsperrenOes($days, $oe)
|
||||
{
|
||||
if(!$oe)
|
||||
{
|
||||
return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'OE Kurzbezeichnung']), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
$von = date('Y-m-d');
|
||||
$bis = date('Y-m-d', strtotime("+{$days} days"));
|
||||
$result = $this->ZeitsperreModel->getMitarbeiterWithZeitsperren($von, $bis, false, false, $oe, false);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function loadZeitsperrenLectorStg($days, $stg)
|
||||
{
|
||||
if(!$stg)
|
||||
{
|
||||
return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Studiengangskennzahl']), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
if(!is_numeric($stg))
|
||||
{
|
||||
return $this->terminateWithError($this->p->t('ui', 'error_paramNoNumber', ['param'=> 'Studiengangskennzahl']), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
|
||||
$von = date('Y-m-d');
|
||||
$bis = date('Y-m-d', strtotime("+{$days} days"));
|
||||
$result = $this->ZeitsperreModel->getMitarbeiterWithZeitsperren($von, $bis, false, true, false, false, $stg);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function getStgLectors()
|
||||
{
|
||||
$sql = "
|
||||
select
|
||||
studiengang_kz,
|
||||
kurzbz,
|
||||
kurzbzlang,
|
||||
typ,
|
||||
bezeichnung,
|
||||
kurzbzlang || ' (' || bezeichnung || ')' AS label,
|
||||
aktiv
|
||||
from
|
||||
public.tbl_studiengang
|
||||
where
|
||||
typ in ('b','m')
|
||||
order by typ asc, kurzbz Asc
|
||||
";
|
||||
|
||||
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
|
||||
$result = $this->StudiengangModel->execReadOnlyQuery($sql);
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function loadZeitsperrenMa($days, $uid)
|
||||
{
|
||||
if ($uid === null || $uid === '')
|
||||
{
|
||||
return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Mitarbeiter UID']), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
$result = $this->ZeitsperreModel->getZeitsperrenForNextDays($days, $uid);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function getDetailsMa($uid)
|
||||
{
|
||||
if ($uid === null || $uid === '')
|
||||
{
|
||||
$this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Mitarbeiter UID']), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
$this->load->model('person/Person_model', 'PersonModel');
|
||||
$result = $this->PersonModel->getFullName($uid);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -62,6 +62,8 @@ class OtherLvPlan extends FHCAPI_Controller
|
||||
"foto" => $profileData->data->foto,
|
||||
"vorname" => $profileData->data->vorname,
|
||||
"nachname" => $profileData->data->nachname,
|
||||
"titel" => $profileData->data->titel,
|
||||
"postnomen" => $profileData->data->postnomen,
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
@@ -0,0 +1,367 @@
|
||||
<?php
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class Zeitsperren extends FHCAPI_Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'getZeitsperrenUser' => ['basis/mitarbeiter:r', 'admin:r', 'assistenz:r'],
|
||||
'getTypenZeitsperren' => self::PERM_LOGGED,
|
||||
'getTypenErreichbarkeit' => self::PERM_LOGGED,
|
||||
'getStunden' => self::PERM_LOGGED,
|
||||
'loadZeitsperre' => ['basis/mitarbeiter:r', 'admin:r', 'assistenz:r'],
|
||||
'add' => ['basis/mitarbeiter:r', 'admin:r', 'assistenz:r'],
|
||||
'update' => ['basis/mitarbeiter:r', 'admin:r', 'assistenz:r'],
|
||||
'delete' => ['basis/mitarbeiter:r', 'admin:r', 'assistenz:r'],
|
||||
]);
|
||||
|
||||
// Load Libraries
|
||||
$this->load->library('VariableLib', ['uid' => getAuthUID()]);
|
||||
$this->load->library('form_validation');
|
||||
|
||||
// Load language phrases
|
||||
$this->loadPhrases([
|
||||
'ui',
|
||||
'person',
|
||||
'zeitsperren'
|
||||
]);
|
||||
|
||||
// Load models
|
||||
$this->load->model('ressource/Zeitsperre_model', 'ZeitsperreModel');
|
||||
$this->load->model('ressource/Zeitsperretyp_model', 'ZeitsperretypModel');
|
||||
$this->load->model('ressource/Erreichbarkeit_model', 'ErreichbarkeitModel');
|
||||
$this->load->model('ressource/Stunde_model', 'StundeModel');
|
||||
$this->load->model('ressource/Zeitaufzeichnung_model', 'ZeitaufzeichnungModel');
|
||||
}
|
||||
|
||||
public function getZeitsperrenUser($uid)
|
||||
{
|
||||
//check if $uid is passedUser
|
||||
$loggedInUser = getAuthUID();
|
||||
if($loggedInUser != $uid) {
|
||||
$this->load->library('PermissionLib');
|
||||
$isAdmin = $this->permissionlib->isBerechtigt('admin');
|
||||
if(!$isAdmin) {
|
||||
$this->terminateWithError($this->p->t('ui', 'noAdmin'), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
}
|
||||
|
||||
$result = $this->ZeitsperreModel->getZeitsperrenUser($uid);
|
||||
|
||||
if (isError($result)) {
|
||||
$this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
$this->terminateWithSuccess((getData($result) ?: []));
|
||||
}
|
||||
|
||||
public function getTypenZeitsperren()
|
||||
{
|
||||
$excludedTypes = array('ZVerfueg');
|
||||
$result = $this->ZeitsperretypModel->getTypenZeitsperren($excludedTypes);
|
||||
if (isError($result)) {
|
||||
$this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
$this->terminateWithSuccess((getData($result) ?: []));
|
||||
}
|
||||
|
||||
public function getTypenErreichbarkeit()
|
||||
{
|
||||
$result = $this->ErreichbarkeitModel->load();
|
||||
if (isError($result)) {
|
||||
$this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
$this->terminateWithSuccess((getData($result) ?: []));
|
||||
}
|
||||
|
||||
public function getStunden()
|
||||
{
|
||||
$this->StundeModel->addOrder('stunde', 'ASC');
|
||||
$result = $this->StundeModel->load();
|
||||
if (isError($result)) {
|
||||
$this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
$this->terminateWithSuccess((getData($result) ?: []));
|
||||
}
|
||||
|
||||
public function loadZeitsperre($zeitsperre_id)
|
||||
{
|
||||
$this->ZeitsperreModel->addSelect(
|
||||
'campus.tbl_zeitsperre.*, typ.*,
|
||||
ma.person_id AS ma_person_id, ma.vorname AS ma_vorname, ma.nachname AS ma_nachname,
|
||||
ma.titelpre AS ma_titelpre, ma.titelpost AS ma_titelpost'
|
||||
);
|
||||
$this->ZeitsperreModel->addJoin('campus.tbl_zeitsperretyp typ', 'ON (typ.zeitsperretyp_kurzbz = campus.tbl_zeitsperre.zeitsperretyp_kurzbz)');
|
||||
$this->ZeitsperreModel->addJoin('public.tbl_benutzer ben', 'ON (ben.uid = campus.tbl_zeitsperre.vertretung_uid)', 'LEFT');
|
||||
$this->ZeitsperreModel->addJoin('public.tbl_person ma', 'ON (ma.person_id = ben.person_id)', 'LEFT');
|
||||
$result = $this->ZeitsperreModel->loadWhere(
|
||||
array('zeitsperre_id' => $zeitsperre_id)
|
||||
);
|
||||
|
||||
if (isError($result)) {
|
||||
$this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
$this->terminateWithSuccess((current(getData($result)) ?: []));
|
||||
}
|
||||
|
||||
public function add($mitarbeiter_uid)
|
||||
{
|
||||
$loggedInUser = getAuthUID();
|
||||
|
||||
if($mitarbeiter_uid != $loggedInUser)
|
||||
$this->terminateWithError($this->p->t('ui', 'noPermission'), self::ERROR_TYPE_GENERAL);
|
||||
|
||||
$this->form_validation->set_rules('zeitsperretyp_kurzbz', 'Grund Zeitsperre', 'required', [
|
||||
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Grund Zeitsperre'])
|
||||
]);
|
||||
|
||||
$this->form_validation->set_rules('vondatum', 'VonDatum', 'required|is_valid_date', [
|
||||
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'VonDatum']),
|
||||
'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'VonDatum'])
|
||||
]);
|
||||
|
||||
$this->form_validation->set_rules('bisdatum', 'BisDatum', 'required|is_valid_date|callback_check_von_bis_datum|callback_check_diff_intval', [
|
||||
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'BisDatum']),
|
||||
'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'BisDatum']),
|
||||
'check_von_bis_datum' => $this->p->t('zeitsperre', 'error_VonDatumGroesserAlsBisDatum'),
|
||||
'check_diff_intval' => $this->p->t('zeitsperre', 'error_zeitraumAuffallendHoch')
|
||||
]);
|
||||
|
||||
if ($this->form_validation->run() == false)
|
||||
{
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
}
|
||||
|
||||
$bezeichnung = $this->input->post('bezeichnung');
|
||||
$vondatum = $this->input->post('vondatum');
|
||||
$vonstunde = $this->input->post('vonstunde');
|
||||
$bisdatum = $this->input->post('bisdatum');
|
||||
$bisstunde = $this->input->post('bisstunde');
|
||||
//$vonIso = $this->input->post('vonISO'); //Timestamp für Stunde
|
||||
//$bisIso = $this->input->post('bisISO'); //Timestamp für Stunde
|
||||
$erreichbarkeit_kurzbz = $this->input->post('erreichbarkeit_kurzbz');
|
||||
$vertretung_uid = $this->input->post('vertretung_uid');
|
||||
$zeitsperretyp_kurzbz = $this->input->post('zeitsperretyp_kurzbz');
|
||||
|
||||
//check if existing zeitsperre
|
||||
$result = $this->ZeitsperreModel->getSperreByDate($mitarbeiter_uid, $vondatum, $vonstunde, true);
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
if(hasData($result))
|
||||
{
|
||||
$this->terminateWithError($this->p->t('zeitsperren', 'error_existingZeitsperre', ['typ'=> current($data)->zeitsperretyp_kurzbz]), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
|
||||
//check if existing zeitaufzeichnung
|
||||
if(in_array($zeitsperretyp_kurzbz, Zeitsperre_model::BLOCKIERENDE_ZEITSPERREN))
|
||||
{
|
||||
$result = $this->ZeitsperreModel->existsZeitaufzeichnung($mitarbeiter_uid, $vondatum, $bisdatum);
|
||||
|
||||
if(hasData($result))
|
||||
$this->terminateWithError($this->p->t('zeitsperren', 'error_existingZeitaufzeichnung'), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
|
||||
$result = $this->ZeitsperreModel->insert(
|
||||
[
|
||||
'mitarbeiter_uid' => $mitarbeiter_uid,
|
||||
'bezeichnung' => $bezeichnung,
|
||||
'vondatum' => $vondatum,
|
||||
'vonstunde' => $vonstunde,
|
||||
'bisdatum' => $bisdatum,
|
||||
'bisstunde' => $bisstunde,
|
||||
'erreichbarkeit_kurzbz' => $erreichbarkeit_kurzbz,
|
||||
'zeitsperretyp_kurzbz' => $zeitsperretyp_kurzbz,
|
||||
'vertretung_uid' => $vertretung_uid,
|
||||
'insertvon' => $loggedInUser,
|
||||
'insertamum' => date('c'),
|
||||
]
|
||||
);
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function update($zeitsperre_id)
|
||||
{
|
||||
//check if loggedin User is owner of the zeitsperre
|
||||
$loggedInUser = getAuthUID();
|
||||
$result = $this->ZeitsperreModel->load($zeitsperre_id);
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
$uid = current($data)->mitarbeiter_uid;
|
||||
|
||||
if($uid != $loggedInUser)
|
||||
$this->terminateWithError($this->p->t('ui', 'noPermission'), self::ERROR_TYPE_GENERAL);
|
||||
|
||||
if(!$zeitsperre_id)
|
||||
{
|
||||
return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Zeitsperre_id']), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
//get current params
|
||||
$array_update = [
|
||||
'bezeichnung',
|
||||
'vondatum',
|
||||
'vonstunde',
|
||||
'bisdatum',
|
||||
'bisstunde',
|
||||
// 'vonISO', //Timestamp für Stunde
|
||||
// 'bisISO', //Timestamp für Stunde
|
||||
'erreichbarkeit_kurzbz',
|
||||
'vertretung_uid',
|
||||
'zeitsperretyp_kurzbz',
|
||||
'mitarbeiter_uid',
|
||||
];
|
||||
$post = $this->input->post();
|
||||
$update = [];
|
||||
|
||||
foreach ($array_update as $prop)
|
||||
{
|
||||
if (array_key_exists($prop, $post))
|
||||
{
|
||||
$update[$prop] = $post[$prop];
|
||||
}
|
||||
}
|
||||
|
||||
// Validation
|
||||
$rulesDefined = false; //necessary, otherwise CI validation will always be triggered, even without rules
|
||||
foreach ($update as $key => $val) {
|
||||
switch ($key) {
|
||||
case 'zeitsperretyp_kurzbz':
|
||||
$this->form_validation->set_rules(
|
||||
$key,
|
||||
'Grund Zeitsperre',
|
||||
'required',
|
||||
['required' => $this->p->t('ui', 'error_fieldRequired', ['field'=>'Grund Zeitsperre'])]
|
||||
);
|
||||
$rulesDefined = true;
|
||||
break;
|
||||
case 'vondatum':
|
||||
$this->form_validation->set_rules(
|
||||
$key,
|
||||
'VonDatum',
|
||||
'required|is_valid_date',
|
||||
[
|
||||
'required' => $this->p->t('ui', 'error_fieldRequired', ['field'=>'VonDatum']),
|
||||
'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field'=>'VonDatum'])
|
||||
]
|
||||
);
|
||||
$rulesDefined = true;
|
||||
break;
|
||||
case 'bisdatum':
|
||||
$rules = 'required|is_valid_date';
|
||||
if (array_key_exists('vondatum', $update)) {
|
||||
$rules .= '|callback_check_von_bis_datum|callback_check_diff_intval';
|
||||
}
|
||||
$this->form_validation->set_rules(
|
||||
$key,
|
||||
'BisDatum',
|
||||
$rules,
|
||||
[
|
||||
'required' => $this->p->t('ui', 'error_fieldRequired', ['field'=>'BisDatum']),
|
||||
'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field'=>'BisDatum']),
|
||||
'check_von_bis_datum' => $this->p->t('zeitsperre', 'error_VonDatumGroesserAlsBisDatum'),
|
||||
'check_diff_intval' => $this->p->t('zeitsperre', 'error_zeitraumAuffallendHoch')
|
||||
]
|
||||
);
|
||||
$rulesDefined = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($rulesDefined && $this->form_validation->run() == false) {
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
}
|
||||
|
||||
if(array_key_exists('vondatum', $post) || array_key_exists('bisdatum', $post))
|
||||
{
|
||||
$result = $this->ZeitsperreModel->load($zeitsperre_id);
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
$data = current($data);
|
||||
|
||||
$mitarbeiter_uid = array_key_exists('mitarbeiter_uid', $post) ? $update['mitarbeiter_uid'] : $data->mitarbeiter_uid;
|
||||
$vondatum = array_key_exists('vondatum', $post) ? $update['vondatum'] : $data->vondatum;
|
||||
$bisdatum = array_key_exists('bisdatum', $post) ? $update['bisdatum'] : $data->bisdatum;
|
||||
$vonstunde = array_key_exists('vonstunde', $post) ? $update['vonstunde'] : $data->vonstunde;
|
||||
$zeitsperretyp_kurzbz = array_key_exists('zeitsperretyp_kurzbz', $post) ? $update['zeitsperretyp_kurzbz'] : $data->zeitsperretyp_kurzbz;
|
||||
|
||||
$result = $this->ZeitsperreModel->getSperreByDate($mitarbeiter_uid, $vondatum, $vonstunde, true);
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
if(hasData($result))
|
||||
{
|
||||
$this->terminateWithError($this->p->t('zeitsperren', 'error_existingZeitsperre', ['typ'=> current($data)->zeitsperretyp_kurzbz]), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
|
||||
//check if existing zeitaufzeichnung
|
||||
if(in_array($zeitsperretyp_kurzbz, Zeitsperre_model::BLOCKIERENDE_ZEITSPERREN))
|
||||
{
|
||||
$result = $this->ZeitsperreModel->existsZeitaufzeichnung($mitarbeiter_uid, $vondatum, $bisdatum);
|
||||
|
||||
if(hasData($result))
|
||||
$this->terminateWithError($this->p->t('zeitsperren', 'error_existingZeitaufzeichnung'), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($update)) {
|
||||
$update['updatevon'] = $loggedInUser;
|
||||
$update['updateamum'] = date('c');
|
||||
$result = $this->ZeitsperreModel->update($zeitsperre_id, $update);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
else
|
||||
$this->terminateWithSuccess("no update");
|
||||
}
|
||||
|
||||
public function delete($zeitsperre_id)
|
||||
{
|
||||
|
||||
if (!is_numeric($zeitsperre_id) || (int)$zeitsperre_id <= 0)
|
||||
{
|
||||
$this->terminateWithError($this->p->t('ui', 'error_missingId', ['id' => 'Zeitsperre_id']), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
|
||||
//check if loggedin User is owner of the zeitsperre
|
||||
$loggedInUser = getAuthUID();
|
||||
$result = $this->ZeitsperreModel->load($zeitsperre_id);
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
$uid = current($data)->mitarbeiter_uid;
|
||||
|
||||
if($uid != $loggedInUser)
|
||||
$this->terminateWithError($this->p->t('ui', 'noPermission'), self::ERROR_TYPE_GENERAL);
|
||||
|
||||
$result = $this->ZeitsperreModel->delete(
|
||||
array('zeitsperre_id' => $zeitsperre_id)
|
||||
);
|
||||
|
||||
if (isError($result)) {
|
||||
$this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
$this->terminateWithSuccess((getData($result) ?: []));
|
||||
}
|
||||
|
||||
public function check_von_bis_datum($bisdatum)
|
||||
{
|
||||
$vondatum = $this->input->post('vondatum');
|
||||
|
||||
return $vondatum <= $bisdatum;
|
||||
}
|
||||
|
||||
public function check_diff_intval($bisdatum)
|
||||
{
|
||||
$vondatum = $this->input->post('vondatum');
|
||||
|
||||
// Intervall in days
|
||||
$vonTs = strtotime($vondatum);
|
||||
$bisTs = strtotime($bisdatum);
|
||||
|
||||
$tage = ($bisTs - $vonTs) / 86400;
|
||||
|
||||
// if intervall > 14
|
||||
return $tage <= 14;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -12,9 +12,9 @@ class Funktionen extends FHCAPI_Controller
|
||||
parent::__construct(array(
|
||||
'getAllFunctions' => ['admin:r', 'assistenz:r'],
|
||||
'getAllUserFunctions' => ['admin:r', 'assistenz:r'],
|
||||
'getOrgHeads' => ['admin:r', 'assistenz:r'],
|
||||
'getOrgetsForCompany' => ['admin:r', 'assistenz:r'],
|
||||
'getAllOrgUnits' => ['admin:r', 'assistenz:r'],
|
||||
'getOrgHeads' => self::PERM_LOGGED,
|
||||
'getOrgetsForCompany' => self::PERM_LOGGED,
|
||||
'getAllOrgUnits' => self::PERM_LOGGED,
|
||||
'loadFunction' => ['admin:r', 'assistenz:r'],
|
||||
'insertFunction' => ['admin:rw', 'assistenz:rw'],
|
||||
'updateFunction' => ['admin:rw', 'assistenz:rw'],
|
||||
|
||||
@@ -28,10 +28,21 @@ class CoreMissingZgvTagLib
|
||||
$this->ci->PrestudentModel->addJoin('public.tbl_prestudentstatus', 'prestudent_id');
|
||||
$this->ci->PrestudentModel->addJoin('public.tbl_benutzer bn', 'person_id');
|
||||
$this->ci->PrestudentModel->addJoin('public.tbl_studiengang', 'studiengang_kz');
|
||||
|
||||
$this->ci->PrestudentModel->db->group_start();
|
||||
|
||||
$this->ci->PrestudentModel->db->where('zgvdatum', null);
|
||||
$this->ci->PrestudentModel->db->where('typ', 'b');
|
||||
|
||||
$this->ci->PrestudentModel->db->or_group_start();
|
||||
$this->ci->PrestudentModel->db->where('zgvmadatum', null);
|
||||
$this->ci->PrestudentModel->db->where('typ', 'm');
|
||||
$this->ci->PrestudentModel->db->group_end();
|
||||
|
||||
$this->ci->PrestudentModel->db->group_end();
|
||||
|
||||
$result = $this->ci->PrestudentModel-> loadWhere(array(
|
||||
'bn.aktiv' => true, //check if necessary
|
||||
'zgvdatum' => null,
|
||||
'typ' => 'b',
|
||||
'bn.aktiv' => true,
|
||||
'studiensemester_kurzbz' => $semester
|
||||
));
|
||||
|
||||
@@ -60,16 +71,36 @@ class CoreMissingZgvTagLib
|
||||
$semester = $params['studiensemester_kurzbz'];
|
||||
$prestudent_id = $params['id'];
|
||||
|
||||
$this->ci->PrestudentModel->addSelect('prestudent_id');
|
||||
$this->ci->PrestudentModel->addSelect('start as von');
|
||||
$this->ci->PrestudentModel->addSelect('ende as bis');
|
||||
$this->ci->PrestudentModel->addJoin('public.tbl_prestudentstatus', 'prestudent_id');
|
||||
|
||||
//add studiensemester also here for manual rebuild
|
||||
$this->ci->PrestudentModel->addJoin('public.tbl_studiensemester', 'studiensemester_kurzbz');
|
||||
|
||||
$this->ci->PrestudentModel->addJoin('public.tbl_benutzer bn', 'person_id');
|
||||
$this->ci->PrestudentModel->addJoin('public.tbl_studiengang', 'studiengang_kz');
|
||||
$result = $this->ci->PrestudentModel->loadWhere(array(
|
||||
'bn.aktiv' => true, //check if necessary
|
||||
'zgvdatum' => null,
|
||||
'typ' => 'b',
|
||||
|
||||
$this->ci->PrestudentModel->db->group_start();
|
||||
|
||||
$this->ci->PrestudentModel->db->where('zgvdatum', null);
|
||||
$this->ci->PrestudentModel->db->where('typ', 'b');
|
||||
|
||||
$this->ci->PrestudentModel->db->or_group_start();
|
||||
$this->ci->PrestudentModel->db->where('zgvmadatum', null);
|
||||
$this->ci->PrestudentModel->db->where('typ', 'm');
|
||||
$this->ci->PrestudentModel->db->group_end();
|
||||
|
||||
$this->ci->PrestudentModel->db->group_end();
|
||||
$this->ci->PrestudentModel->db->limit(1);
|
||||
|
||||
$result = $this->ci->PrestudentModel-> loadWhere(array(
|
||||
'bn.aktiv' => true,
|
||||
'studiensemester_kurzbz' => $semester,
|
||||
'prestudent_id' => $prestudent_id
|
||||
));
|
||||
|
||||
if(hasData($result))
|
||||
{
|
||||
return $result;
|
||||
|
||||
@@ -13,6 +13,7 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl
|
||||
protected $dienstverhaeltnis_id;
|
||||
protected $vertragsbestandteil_id;
|
||||
protected $gehaltstyp_kurzbz;
|
||||
protected $gehaltsanpassungtyp_kurzbz = '';
|
||||
protected $von;
|
||||
protected $bis;
|
||||
protected $anmerkung;
|
||||
@@ -21,6 +22,7 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl
|
||||
protected $valorisierungssperre;
|
||||
protected $valorisierung;
|
||||
protected $auszahlungen;
|
||||
protected $gehaltstyp_bezeichnung;
|
||||
|
||||
protected $insertamum;
|
||||
protected $insertvon;
|
||||
@@ -39,6 +41,10 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl
|
||||
isset($data->dienstverhaeltnis_id) && $this->setDienstverhaeltnis_id($data->dienstverhaeltnis_id);
|
||||
isset($data->vertragsbestandteil_id) && $this->setVertragsbestandteil_id($data->vertragsbestandteil_id);
|
||||
isset($data->gehaltstyp_kurzbz) && $this->setGehaltstyp_kurzbz($data->gehaltstyp_kurzbz);
|
||||
//isset($data->gehaltsanpassungtyp_kurzbz) && $this->setGehaltsanpassungtyp_kurzbz($data->gehaltsanpassungtyp_kurzbz);
|
||||
if (!empty($data->gehaltsanpassungtyp_kurzbz)) {
|
||||
$this->setGehaltsanpassungtyp_kurzbz($data->gehaltsanpassungtyp_kurzbz);
|
||||
}
|
||||
isset($data->von) && $this->setVon($data->von);
|
||||
isset($data->bis) && $this->setBis($data->bis);
|
||||
isset($data->anmerkung) && $this->setAnmerkung($data->anmerkung);
|
||||
@@ -47,7 +53,8 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl
|
||||
isset($data->valorisierungssperre) && $this->setValorisierungssperre($data->valorisierungssperre);
|
||||
isset($data->valorisierung) && $this->setValorisierung($data->valorisierung);
|
||||
isset($data->auszahlungen) && $this->setAuszahlungen($data->auszahlungen);
|
||||
|
||||
isset($data->gehaltstyp_bezeichnung) && $this->setGehaltstyp_bezeichnung($data->gehaltstyp_bezeichnung);
|
||||
|
||||
isset($data->insertamum) && $this->setInsertamum($data->insertamum);
|
||||
isset($data->insertvon) && $this->setInsertvon($data->insertvon);
|
||||
isset($data->updateamum) && $this->setUpdateamum($data->updateamum);
|
||||
@@ -75,6 +82,11 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl
|
||||
return $this->gehaltstyp_kurzbz;
|
||||
}
|
||||
|
||||
public function getGehaltsanpassungtyp_kurzbz()
|
||||
{
|
||||
return $this->gehaltsanpassungtyp_kurzbz;
|
||||
}
|
||||
|
||||
public function getVon()
|
||||
{
|
||||
return $this->von;
|
||||
@@ -178,6 +190,13 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setGehaltsanpassungtyp_kurzbz($gehaltsanpassungtyp_kurzbz)
|
||||
{
|
||||
$this->markDirty('gehaltsanpassungtyp_kurzbz', $this->gehaltsanpassungtyp_kurzbz, $gehaltsanpassungtyp_kurzbz);
|
||||
$this->gehaltsanpassungtyp_kurzbz = $gehaltsanpassungtyp_kurzbz;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setVon($von)
|
||||
{
|
||||
$this->markDirty('von', $this->von, $von);
|
||||
@@ -206,6 +225,10 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl
|
||||
$grundbetrag = number_format($grundbetrag, 2, '.', '');
|
||||
}
|
||||
$this->markDirty('grundbetrag', $this->grundbetrag, $grundbetrag);
|
||||
if(in_array('grundbetrag', $this->modifiedcolumns))
|
||||
{
|
||||
$this->setBetrag_valorisiert($grundbetrag);
|
||||
}
|
||||
$this->grundbetrag = $grundbetrag;
|
||||
return $this;
|
||||
}
|
||||
@@ -242,6 +265,13 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setGehaltstyp_bezeichnung($gehaltstyp_bezeichnung)
|
||||
{
|
||||
$this->markDirty('gehaltstyp_bezeichnung', $this->gehaltstyp_bezeichnung, $gehaltstyp_bezeichnung);
|
||||
$this->gehaltstyp_bezeichnung = $gehaltstyp_bezeichnung;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setInsertamum($insertamum)
|
||||
{
|
||||
$this->markDirty('insertamum', $this->insertamum, $insertamum);
|
||||
@@ -284,6 +314,7 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl
|
||||
'dienstverhaeltnis_id' => $this->getDienstverhaeltnis_id(),
|
||||
'vertragsbestandteil_id' => $this->getVertragsbestandteil_id(),
|
||||
'gehaltstyp_kurzbz' => $this->getGehaltstyp_kurzbz(),
|
||||
'gehaltsanpassungtyp_kurzbz' => $this->getGehaltsanpassungtyp_kurzbz(),
|
||||
'von' => $this->getVon(),
|
||||
'bis' => $this->getBis(),
|
||||
'anmerkung' => $this->getAnmerkung(),
|
||||
@@ -312,6 +343,7 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl
|
||||
dienstverhaeltnis_id: {$this->getDienstverhaeltnis_id()}
|
||||
vertragsbestandteil_id: {$this->getVertragsbestandteil_id()}
|
||||
gehaltstyp_kurzbz: {$this->getGehaltstyp_kurzbz()}
|
||||
gehaltsanpassungtyp_kurzbz: {$this->getGehaltsanpassungtyp_kurzbz()}
|
||||
von: {$this->getVon()}
|
||||
bis: {$this->getBis()}
|
||||
anmerkung: {$this->getAnmerkung()}
|
||||
|
||||
@@ -457,6 +457,7 @@ class Studiengang_model extends DB_Model
|
||||
*/
|
||||
public function getLeitung($studiengang_kz = null)
|
||||
{
|
||||
$this->addDistinct();
|
||||
$this->addSelect('uid, studiengang_kz, oe_kurzbz, vorname, nachname, email, titelpre, titelpost, alias');
|
||||
$this->addJoin('public.tbl_benutzerfunktion', 'oe_kurzbz');
|
||||
$this->addJoin('public.tbl_benutzer', 'uid');
|
||||
|
||||
@@ -12,6 +12,8 @@ class Zeitsperre_model extends DB_Model
|
||||
$this->pk = 'zeitsperre_id';
|
||||
}
|
||||
|
||||
const BLOCKIERENDE_ZEITSPERREN = ['Krank','Urlaub','ZA','DienstV','PflegeU','DienstF','CovidSB','CovidKS'];
|
||||
|
||||
/**
|
||||
* Save or update Zeitsperre.
|
||||
*
|
||||
@@ -62,6 +64,271 @@ class Zeitsperre_model extends DB_Model
|
||||
return $this->execQuery($qry);
|
||||
}
|
||||
|
||||
/**
|
||||
* get Zeitsperren of a user
|
||||
*
|
||||
* @param $uid mitarbeiteruid
|
||||
* @param $bisgrenze @true show only entries of actual business year (1.9.- 31.8.)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getZeitsperrenUser($uid, $bisgrenze = true)
|
||||
{
|
||||
$qry = "
|
||||
SELECT
|
||||
tbl_zeitsperre.*, tbl_zeitsperretyp.*, tbl_erreichbarkeit.farbe AS erreichbarkeit_farbe,
|
||||
tbl_erreichbarkeit.beschreibung AS erreichbarkeit_beschreibung,
|
||||
CONCAT (ps.vorname, ' ', ps.nachname) as vertretung
|
||||
FROM (campus.tbl_zeitsperre JOIN campus.tbl_zeitsperretyp USING (zeitsperretyp_kurzbz))
|
||||
LEFT JOIN campus.tbl_erreichbarkeit USING (erreichbarkeit_kurzbz)
|
||||
LEFT JOIN public.tbl_benutzer ON campus.tbl_zeitsperre.vertretung_uid = public.tbl_benutzer.uid
|
||||
LEFT JOIN public.tbl_person ps USING (person_id)
|
||||
WHERE mitarbeiter_uid= ?
|
||||
";
|
||||
|
||||
if($bisgrenze)
|
||||
{
|
||||
$qry.="
|
||||
AND (
|
||||
(date_part('month',vondatum)>=9 AND date_part('year', vondatum)>='".(date('Y')-1)."')
|
||||
OR
|
||||
(date_part('month',vondatum)<9 AND date_part('year', vondatum)>='".(date('Y'))."')
|
||||
)";
|
||||
}
|
||||
|
||||
$qry.= " ORDER BY vondatum DESC";
|
||||
|
||||
return $this->execQuery($qry, array('mitarbeiter_uid' => $uid));
|
||||
}
|
||||
|
||||
/**
|
||||
* check a date for existing zeitsperre
|
||||
*
|
||||
* @param $uid mitarbeiteruid
|
||||
* @param $datum datum to check
|
||||
* @param $stunde stunde (default = null)
|
||||
* @param bool $nurblockierend if only hr relevante zeitsperren have to be checked
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSperreByDate($uid, $datum, $stunde = null, $nurblockierend = false)
|
||||
{
|
||||
$parametersArray = [$datum, $datum];
|
||||
|
||||
$qry = "
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
campus.tbl_zeitsperre
|
||||
WHERE
|
||||
vondatum <= ?
|
||||
AND bisdatum>= ?";
|
||||
|
||||
if($nurblockierend)
|
||||
{
|
||||
$qry .= " AND zeitsperretyp_kurzbz IN ('"
|
||||
. implode("','", self::BLOCKIERENDE_ZEITSPERREN)
|
||||
. "')";
|
||||
}
|
||||
|
||||
if(!is_null($stunde))
|
||||
{
|
||||
$parametersArray = array_merge(
|
||||
$parametersArray,
|
||||
[$datum, $stunde, $datum, $datum, $stunde, $datum]
|
||||
);
|
||||
|
||||
$qry.=" AND
|
||||
((vondatum= ? AND vonstunde<= ? OR vonstunde is null OR vondatum<> ?) AND
|
||||
(bisdatum= ? AND bisstunde>= ? OR bisstunde is null OR bisdatum<> ?))";
|
||||
}
|
||||
|
||||
array_push($parametersArray, $uid);
|
||||
|
||||
$qry .= "AND mitarbeiter_uid= ? ";
|
||||
|
||||
return $this->execQuery($qry, $parametersArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* check a date for existing zeitsperre
|
||||
*
|
||||
* @param $uid mitarbeiteruid
|
||||
* @param $vondatum datum in Format IS0
|
||||
* @param $bisdatum datum in Format ISO
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function existsZeitaufzeichnung($uid, $vonDay, $bisDay)
|
||||
{
|
||||
try {
|
||||
$from = new DateTime($vonDay);
|
||||
$to = new DateTime($bisDay);
|
||||
} catch (Exception $e) {
|
||||
throw new Exception("Invalid date format");
|
||||
}
|
||||
|
||||
//remove hour stamps
|
||||
$from->setTime(0, 0, 0);
|
||||
$to->setTime(0, 0, 0)->modify('+1 day');
|
||||
|
||||
$fromSql = $from->format('Y-m-d');
|
||||
$toSql = $to->format('Y-m-d');
|
||||
$params = [$uid, $fromSql, $toSql];
|
||||
|
||||
$qry = "
|
||||
SELECT *
|
||||
FROM campus.tbl_zeitaufzeichnung
|
||||
WHERE uid = ?
|
||||
AND start >= ?
|
||||
AND ende < ? ";
|
||||
|
||||
$result = $this->execQuery($qry, $params);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* getZeitsperren of Mitarbeiter for the next days
|
||||
* @ days: count of the intervall of the next days
|
||||
* @return array
|
||||
*/
|
||||
public function getZeitsperrenForNextDays($days, $uid=null)
|
||||
{
|
||||
$von = date('Y-m-d');
|
||||
$bis = date('Y-m-d', strtotime("+{$days} days"));
|
||||
|
||||
$paramsArray = [$von, $bis, $bis, $von];
|
||||
|
||||
if($uid)
|
||||
$paramsArray[] = $uid;
|
||||
|
||||
$qry = "select
|
||||
nachname,
|
||||
vorname,
|
||||
uid,
|
||||
vondatum,
|
||||
bisdatum,
|
||||
vertretung_uid,
|
||||
erreichbarkeit_kurzbz,
|
||||
mv.kurzbz
|
||||
from
|
||||
campus.vw_mitarbeiter
|
||||
join campus.tbl_zeitsperre on
|
||||
(uid = mitarbeiter_uid)
|
||||
left join public.tbl_mitarbeiter mv on campus.tbl_zeitsperre.vertretung_uid = mv.mitarbeiter_uid
|
||||
where
|
||||
((? <= bisdatum
|
||||
and ? >= bisdatum)
|
||||
or (?>= vondatum
|
||||
and ? <= vondatum))";
|
||||
|
||||
if($uid)
|
||||
$qry .= " and uid = ? ";
|
||||
|
||||
$qry .= "
|
||||
order by nachname
|
||||
";
|
||||
|
||||
$result = $this->execQuery($qry, $paramsArray);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getMitarbeiterWithZeitsperren($von, $bis, $fix=false, $lector=false, $oe=null, $ass=false, $stg=false)
|
||||
{
|
||||
$paramsArray = [$von, $bis, $bis, $von];
|
||||
|
||||
if($oe)
|
||||
{
|
||||
$paramsArray[] = $oe;
|
||||
}
|
||||
|
||||
if($stg)
|
||||
{
|
||||
$paramsArray[] = $stg;
|
||||
}
|
||||
|
||||
$qry = "
|
||||
SELECT
|
||||
m.nachname,
|
||||
m.vorname,
|
||||
m.uid,
|
||||
z.vondatum,
|
||||
z.bisdatum,
|
||||
z.vertretung_uid,
|
||||
z.erreichbarkeit_kurzbz,
|
||||
m.lektor,
|
||||
m.fixangestellt,
|
||||
mv.kurzbz
|
||||
FROM campus.vw_mitarbeiter m
|
||||
join public.tbl_benutzer bn on bn.uid = m.uid";
|
||||
|
||||
if($oe || $ass || $stg)
|
||||
{
|
||||
$qry .= " JOIN public.tbl_benutzerfunktion bf on bf.uid = bn.uid";
|
||||
}
|
||||
|
||||
if($stg)
|
||||
{
|
||||
$qry .= " JOIN public.tbl_studiengang stg using (oe_kurzbz)";
|
||||
}
|
||||
|
||||
$qry.= "
|
||||
LEFT JOIN campus.tbl_zeitsperre z
|
||||
ON m.uid = z.mitarbeiter_uid
|
||||
AND (
|
||||
(? <= z.bisdatum AND ? >= z.bisdatum)
|
||||
OR
|
||||
(? >= z.vondatum AND ? <= z.vondatum)
|
||||
)
|
||||
left join public.tbl_mitarbeiter mv on z.vertretung_uid = mv.mitarbeiter_uid
|
||||
where bn.aktiv = true
|
||||
";
|
||||
|
||||
|
||||
if($fix) {
|
||||
$qry.= " AND m.fixangestellt = true";
|
||||
}
|
||||
if($lector) {
|
||||
$qry.= " AND m.lektor = true";
|
||||
}
|
||||
|
||||
if ($oe)
|
||||
{
|
||||
$qry.= "
|
||||
AND bf.funktion_kurzbz ='oezuordnung'
|
||||
AND bf.oe_kurzbz= ?
|
||||
AND (bf.datum_von is null or bf.datum_von <=now())
|
||||
AND (bf.datum_bis is null or bf.datum_bis >= now())
|
||||
";
|
||||
}
|
||||
|
||||
if ($ass)
|
||||
{
|
||||
$qry.= "
|
||||
AND bf.funktion_kurzbz ='ass'
|
||||
AND (bf.datum_von is null or bf.datum_von <=now())
|
||||
AND (bf.datum_bis is null or bf.datum_bis >= now())
|
||||
";
|
||||
}
|
||||
|
||||
if ($stg)
|
||||
{
|
||||
$qry.= "
|
||||
AND stg.studiengang_kz = ?
|
||||
";
|
||||
}
|
||||
|
||||
$qry .= " order by nachname, vorname, uid";
|
||||
|
||||
|
||||
$result = $this->execQuery($qry, $paramsArray);
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
public function checkIfZeitsperreExists($uid, $datum, $stunde)
|
||||
{
|
||||
$this->db->select("*");
|
||||
@@ -71,27 +338,27 @@ class Zeitsperre_model extends DB_Model
|
||||
|
||||
$this->db->group_start();
|
||||
|
||||
$this->db->where('vondatum <', $datum);
|
||||
$this->db->or_group_start();
|
||||
$this->db->where('vondatum', $datum);
|
||||
$this->db->group_start();
|
||||
$this->db->where('vonstunde <=', $stunde);
|
||||
$this->db->or_where('vonstunde IS NULL', null, false);
|
||||
$this->db->group_end();
|
||||
$this->db->group_end();
|
||||
$this->db->where('vondatum <', $datum);
|
||||
$this->db->or_group_start();
|
||||
$this->db->where('vondatum', $datum);
|
||||
$this->db->group_start();
|
||||
$this->db->where('vonstunde <=', $stunde);
|
||||
$this->db->or_where('vonstunde IS NULL', null, false);
|
||||
$this->db->group_end();
|
||||
$this->db->group_end();
|
||||
$this->db->group_end();
|
||||
|
||||
|
||||
$this->db->group_start();
|
||||
$this->db->where('bisdatum >', $datum);
|
||||
$this->db->or_group_start();
|
||||
$this->db->where('bisdatum', $datum);
|
||||
$this->db->group_start();
|
||||
$this->db->where('bisstunde >=', $stunde);
|
||||
$this->db->or_where('bisstunde IS NULL', null, false);
|
||||
$this->db->group_end();
|
||||
$this->db->where('bisdatum >', $datum);
|
||||
$this->db->or_group_start();
|
||||
$this->db->where('bisdatum', $datum);
|
||||
$this->db->group_start();
|
||||
$this->db->where('bisstunde >=', $stunde);
|
||||
$this->db->or_where('bisstunde IS NULL', null, false);
|
||||
$this->db->group_end();
|
||||
|
||||
$this->db->group_end();
|
||||
$this->db->group_end();
|
||||
$this->db->group_end();
|
||||
|
||||
return $this->load();
|
||||
|
||||
@@ -11,4 +11,20 @@ class Zeitsperretyp_model extends DB_Model
|
||||
$this->dbTable = 'campus.tbl_zeitsperretyp';
|
||||
$this->pk = 'zeitsperretyp_kurzbz';
|
||||
}
|
||||
|
||||
public function getTypenZeitsperren($excludedTypes = [])
|
||||
{
|
||||
$whereNotClause = "";
|
||||
if (count($excludedTypes)) {
|
||||
$excludedTypes = array_map(
|
||||
function ($type) {
|
||||
return "'$type'";
|
||||
},
|
||||
$excludedTypes
|
||||
);
|
||||
$excludedTypes = implode(", ", $excludedTypes);
|
||||
$whereNotClause = "WHERE NOT zeitsperretyp_kurzbz IN ($excludedTypes)";
|
||||
}
|
||||
return $this->execQuery("SELECT * FROM $this->dbTable $whereNotClause ORDER BY beschreibung ASC");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ with gbt as (
|
||||
gb.anmerkung,
|
||||
gb.dienstverhaeltnis_id,
|
||||
gb.gehaltstyp_kurzbz,
|
||||
gb.gehaltsanpassungtyp_kurzbz,
|
||||
gb.valorisierungssperre,
|
||||
gb.valorisierung,
|
||||
gb.grundbetrag as grund_betrag_decrypted,
|
||||
@@ -76,11 +77,13 @@ select
|
||||
gbt.anmerkung,
|
||||
gbt.dienstverhaeltnis_id,
|
||||
gbt.gehaltstyp_kurzbz,
|
||||
gbt.gehaltsanpassungtyp_kurzbz,
|
||||
gbt.valorisierungssperre,
|
||||
gbt.valorisierung,
|
||||
gbt.grund_betrag_decrypted,
|
||||
gbt.betrag_val_decrypted,
|
||||
gt.bezeichnung as gehaltstyp_bezeichnung,
|
||||
ga.bezeichnung as gehaltsanpassungtyp_bezeichnung,
|
||||
vb.vertragsbestandteiltyp_kurzbz,
|
||||
bf.funktion_kurzbz,
|
||||
bf.oe_kurzbz,
|
||||
@@ -93,6 +96,8 @@ from
|
||||
gbt
|
||||
LEFT JOIN
|
||||
hr.tbl_gehaltstyp gt using(gehaltstyp_kurzbz)
|
||||
LEFT JOIN
|
||||
hr.tbl_gehaltsanpassungtyp ga using(gehaltsanpassungtyp_kurzbz)
|
||||
LEFT JOIN
|
||||
hr.tbl_vertragsbestandteil vb using(vertragsbestandteil_id)
|
||||
LEFT JOIN
|
||||
@@ -177,7 +182,8 @@ LEFT JOIN
|
||||
$stichtagclause .= ')';
|
||||
}
|
||||
|
||||
$this->addSelect('*');
|
||||
$this->addSelect('tbl_gehaltsbestandteil.*, tbl_gehaltstyp.bezeichnung AS gehaltstyp_bezeichnung');
|
||||
$this->addJoin('hr.tbl_gehaltstyp', 'gehaltstyp_kurzbz');
|
||||
$where = <<<EOSQL
|
||||
dienstverhaeltnis_id = {$this->escape($dienstverhaeltnis_id)}
|
||||
{$stichtagclause}
|
||||
@@ -202,6 +208,7 @@ SELECT
|
||||
g.dienstverhaeltnis_id,
|
||||
g.vertragsbestandteil_id,
|
||||
g.gehaltstyp_kurzbz,
|
||||
g.gehaltsanpassungtyp_kurzbz,
|
||||
g.von,
|
||||
g.bis,
|
||||
g.anmerkung,
|
||||
@@ -213,9 +220,11 @@ SELECT
|
||||
g.updateamum,
|
||||
g.updatevon,
|
||||
g.valorisierung,
|
||||
g.auszahlungen
|
||||
g.auszahlungen,
|
||||
gt.bezeichnung AS gehaltstyp_bezeichnung
|
||||
FROM
|
||||
hr.tbl_gehaltsbestandteil g
|
||||
hr.tbl_gehaltsbestandteil g
|
||||
JOIN hr.tbl_gehaltstyp gt USING (gehaltstyp_kurzbz)
|
||||
LEFT JOIN
|
||||
hr.tbl_valorisierung_historie vh ON vh.gehaltsbestandteil_id = g.gehaltsbestandteil_id AND vh.valorisierungsdatum = (
|
||||
SELECT
|
||||
@@ -263,7 +272,7 @@ EOSQL;
|
||||
// Note: replaced gb.betrag_valorisiert with vh.betrag_valorisiert!
|
||||
$qry = "
|
||||
SELECT
|
||||
gb.gehaltsbestandteil_id,gb.dienstverhaeltnis_id,gb.vertragsbestandteil_id,gb.gehaltstyp_kurzbz,
|
||||
gb.gehaltsbestandteil_id,gb.dienstverhaeltnis_id,gb.vertragsbestandteil_id,gb.gehaltstyp_kurzbz,gb.gehaltsanpassungtyp_kurzbz,
|
||||
gb.von,gb.bis,gb.anmerkung,gb.grundbetrag as grundbetrag,gb.valorisierungssperre,gb.insertamum,
|
||||
gb.insertvon,gb.updateamum,gb.updatevon,gb.valorisierung,gb.auszahlungen,
|
||||
vh.valorisierungsdatum, vh.betrag_valorisiert as betrag_valorisiert
|
||||
|
||||
@@ -23,7 +23,9 @@ $includesArray = array(
|
||||
'public/css/components/FormUnderline.css',
|
||||
'public/css/components/abgabetool/abgabe.css',
|
||||
'public/css/Cis4/Cms.css',
|
||||
'public/css/Cis4/Studium.css'
|
||||
'public/css/Cis4/Studium.css',
|
||||
'public/css/components/Zeitsperrenma.css', //70747
|
||||
'public/css/Cis4/Zeitsperren.css', //77941
|
||||
),
|
||||
'customJSs' => array(
|
||||
'vendor/npm-asset/primevue/accordion/accordion.min.js',
|
||||
|
||||
@@ -12,13 +12,13 @@ $includesArray = array(
|
||||
'tinymce5' => true,
|
||||
'phrases' => array(
|
||||
'global',
|
||||
'ui',
|
||||
'ui'
|
||||
),
|
||||
'customCSSs' => [
|
||||
'public/css/components/vue-datepicker.css',
|
||||
'public/css/components/primevue.css',
|
||||
'public/css/Vertragsverwaltung.css',
|
||||
'public/css/components/Detailheader.css'
|
||||
'public/css/components/Detailheader.css',
|
||||
],
|
||||
'customJSs' => [
|
||||
#'vendor/npm-asset/primevue/tree/tree.min.js',
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/* Repositioning clear icon Datepicker for not being outside the textfield */
|
||||
/* Wrapper */
|
||||
.dp__input_wrap {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* calender-Icon left */
|
||||
.dp__input_icon {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
right: auto;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
/* Clear-Icon right */
|
||||
.dp__clear_icon {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
left: auto;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
/* padding for Icons */
|
||||
.dp__input {
|
||||
padding-left: 36px !important;
|
||||
padding-right: 36px !important;
|
||||
}
|
||||
|
||||
.info-feedback {
|
||||
display: block;
|
||||
font-size: 0.875em;
|
||||
color: #0d6efd; /* Bootstrap primary */
|
||||
}
|
||||
|
||||
.is-info {
|
||||
border-color: #0d6efd;
|
||||
}
|
||||
@@ -62,3 +62,16 @@
|
||||
top:13%;"
|
||||
z-index: 104; font-size: 1rem; width: 2.5rem; height: 2.5rem; opacity:0; transition: opacity 0.2s; top:13%;"
|
||||
}*/
|
||||
|
||||
.tag-hover:hover {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
|
||||
.green {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
|
||||
.btn-hover {
|
||||
--bs-btn-hover-bg: #e9ecef; /* Neue Hintergrundfarbe beim Hover */
|
||||
--bs-btn-hover-border-color: #e9ecef; /* Neue Rahmenfarbe beim Hover */
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
.item-inactive {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.table-scroll {
|
||||
height: calc(100vh - 300px);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.zeitsperrenma-content thead th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: white;
|
||||
z-index: 2;
|
||||
}
|
||||
@@ -145,3 +145,8 @@
|
||||
float: right;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.btn-hover {
|
||||
--bs-btn-hover-bg: #e9ecef;
|
||||
--bs-btn-hover-border-color: #e9ecef;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (C) 2026 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 {
|
||||
getTimelocksUser(uid) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/Zeitsperren/getZeitsperrenUser/' + uid
|
||||
};
|
||||
},
|
||||
getTypenZeitsperren(){
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/Zeitsperren/getTypenZeitsperren/'
|
||||
};
|
||||
},
|
||||
getTypenErreichbarkeit(){
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/Zeitsperren/getTypenErreichbarkeit/'
|
||||
};
|
||||
},
|
||||
getStunden(){
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/Zeitsperren/getStunden/'
|
||||
};
|
||||
},
|
||||
addZeitsperre(uid, params) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/Zeitsperren/add/' + uid,
|
||||
params
|
||||
};
|
||||
},
|
||||
editZeitsperre(zeitsperre_id, params) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/Zeitsperren/update/' + zeitsperre_id,
|
||||
params
|
||||
};
|
||||
},
|
||||
loadZeitsperre(zeitsperre_id) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/Zeitsperren/loadZeitsperre/' + zeitsperre_id
|
||||
};
|
||||
},
|
||||
deleteZeitsperre(zeitsperre_id) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/Zeitsperren/delete/' + zeitsperre_id
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Copyright (C) 2026 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 {
|
||||
loadAllActiveZeitsperren(days) {
|
||||
return {
|
||||
method: 'get',
|
||||
url:'api/frontend/v1/MaZeitsperren/getAllActiveZeitsperren/' + days
|
||||
};
|
||||
},
|
||||
loadAllZeitsperrenFixeMa(days) {
|
||||
return {
|
||||
method: 'get',
|
||||
url:'api/frontend/v1/MaZeitsperren/getAllZeitsperrenFixeMa/' + days
|
||||
};
|
||||
},
|
||||
loadAllZeitsperrenLector(days) {
|
||||
return {
|
||||
method: 'get',
|
||||
url:'api/frontend/v1/MaZeitsperren/getAllZeitsperrenLector/' + days
|
||||
};
|
||||
},
|
||||
getAllOes(){
|
||||
return {
|
||||
method: 'get',
|
||||
url:'api/frontend/v1/funktionen/Funktionen/getAllOrgUnits'
|
||||
};
|
||||
},
|
||||
loadAllZeitsperrenOE(days, oe) {
|
||||
return {
|
||||
method: 'get',
|
||||
url:'api/frontend/v1/MaZeitsperren/getAllZeitsperrenOes/' + days + '/' + oe,
|
||||
};
|
||||
},
|
||||
loadZeitsperrenAss(days) {
|
||||
return {
|
||||
method: 'get',
|
||||
url:'api/frontend/v1/MaZeitsperren/getZeitsperrenAss/' + days
|
||||
};
|
||||
},
|
||||
getAllStg(){
|
||||
return {
|
||||
method: 'get',
|
||||
url:'api/frontend/v1/MaZeitsperren/getStgLectors'
|
||||
};
|
||||
},
|
||||
loadZeitsperrenLectorStg(days,stg) {
|
||||
return {
|
||||
method: 'get',
|
||||
url:'api/frontend/v1/MaZeitsperren/loadZeitsperrenLectorStg/' + days + '/' + stg,
|
||||
};
|
||||
},
|
||||
loadZeitsperrenMa(days, uid) {
|
||||
return {
|
||||
method: 'get',
|
||||
url:'api/frontend/v1/MaZeitsperren/loadZeitsperrenMa/' + days + '/' + uid,
|
||||
};
|
||||
},
|
||||
getDetailsMa(uid){
|
||||
return {
|
||||
method: 'get',
|
||||
url:'api/frontend/v1/MaZeitsperren/getDetailsMa/' + uid,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ import DeadlineOverview from "../../components/Cis/Abgabetool/DeadlineOverview.j
|
||||
import Studium from "../../components/Cis/Studium/Studium.js";
|
||||
import StgOrgLvPlan from "../../components/Cis/LvPlan/StgOrg.js";
|
||||
import OtherLvPlan from "../../components/Cis/LvPlan/OtherLvPlan.js";
|
||||
import ZeitsperrenMa from "../../components/Cis/ZeitsperrenMitarbeiter/ZeitsperrenMa.js";
|
||||
import Zeitsperren from "../../components/Cis/Zeitsperren/Zeitsperren.js";
|
||||
|
||||
import ApiRouteInfo from '../../api/factory/routeinfo.js';
|
||||
import {capitalize} from "../../helpers/StringHelpers.js";
|
||||
@@ -231,6 +233,23 @@ const router = VueRouter.createRouter({
|
||||
component: FhcDashboard,
|
||||
props: {dashboard: 'CIS'},
|
||||
},
|
||||
{
|
||||
path: '/Cis/Zeitsperrenma/:type(all|fix|lector|ma|oe|stg|ass)?/:id?/:days?',
|
||||
name: 'ZeitsperrenMa',
|
||||
component: ZeitsperrenMa,
|
||||
props: route => {
|
||||
//console.log('ROUTE PARAMS', route.params);
|
||||
return {
|
||||
propsViewData: route.params
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
path: `/Cis/Zeitsperren`,
|
||||
name: 'Zeitsperren',
|
||||
component: Zeitsperren,
|
||||
props: true
|
||||
},
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
name: 'Fallback',
|
||||
|
||||
@@ -174,6 +174,9 @@ export default {
|
||||
>
|
||||
{{ $p.t('lehre/noLvFound') }}
|
||||
</div>
|
||||
<div v-else-if="!renderers || !renderers[event.type]" class="placeholder-glow">
|
||||
<span class="placeholder col-12"></span>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
:class="'event-type-' + event.type + ' ' + mode + 'PageContainer'"
|
||||
|
||||
@@ -79,6 +79,9 @@ export default {
|
||||
>
|
||||
{{ $p.t('lehre/noLvFound') }}
|
||||
</div>
|
||||
<div v-else-if="!renderers || !renderers[event.type]" class="placeholder-glow">
|
||||
<span class="placeholder col-12"></span>
|
||||
</div>
|
||||
<component
|
||||
v-else-if="mode == 'eventheader'"
|
||||
:is="renderers[event.type]?.modalTitle"
|
||||
|
||||
@@ -32,7 +32,7 @@ export default {
|
||||
listGroup: [],
|
||||
rangeIntervalFirst: null,
|
||||
otherPersonData: {
|
||||
fullName: "",
|
||||
fullNameWithTitle: "",
|
||||
photo: "",
|
||||
},
|
||||
timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone,
|
||||
@@ -210,10 +210,17 @@ export default {
|
||||
this.isOtherPersonMitarbeiter =
|
||||
!!viewData?.user_data?.is_mitarbeiter;
|
||||
this.isOtherPersonStudent = !!viewData?.user_data?.is_student;
|
||||
this.otherPersonData.fullName =
|
||||
viewData?.user_data?.vorname +
|
||||
" " +
|
||||
viewData?.user_data?.nachname;
|
||||
let fullNameWithTitleFragments = [
|
||||
viewData?.user_data?.titel,
|
||||
viewData?.user_data?.vorname,
|
||||
viewData?.user_data?.nachname,
|
||||
viewData?.user_data?.postnomen,
|
||||
];
|
||||
fullNameWithTitleFragments = fullNameWithTitleFragments.filter(
|
||||
(fragment) => !!fragment,
|
||||
);
|
||||
this.otherPersonData.fullNameWithTitle =
|
||||
fullNameWithTitleFragments.join(" ");
|
||||
this.otherPersonData.photo = viewData?.user_data?.foto;
|
||||
},
|
||||
async redirectToMyLvPlanIfAuthUid() {
|
||||
@@ -225,12 +232,21 @@ export default {
|
||||
this.$router.push({ name: "MyLvPlan" });
|
||||
}
|
||||
},
|
||||
copyFullNameWithTitleToClipboard() {
|
||||
navigator.clipboard.writeText(
|
||||
this.otherPersonData.fullNameWithTitle,
|
||||
);
|
||||
this.$fhcAlert.alertSuccess(
|
||||
this.$p.t("profil/name_title_clipboard_copy_confirmation"),
|
||||
);
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
await this.redirectToMyLvPlanIfAuthUid();
|
||||
await this.fetchViewData();
|
||||
await this.$p.loadCategory(["profil"]);
|
||||
},
|
||||
template: `
|
||||
template: /*html*/ `
|
||||
<div class="d-flex flex-column h-100">
|
||||
<h2>
|
||||
<div class="d-flex flex-row justify-content-between align-items-center">
|
||||
@@ -238,8 +254,11 @@ export default {
|
||||
{{ $p.t('lehre/stundenplan') + (studiensemester_kurzbz ? " " + studiensemester_kurzbz : "") }}
|
||||
</span>
|
||||
<div @click="this.$router.push({name: 'ProfilView', params: {uid: propsViewData.otherUid}})" type="button" class="d-flex flex-row align-items-center gap-3">
|
||||
<span v-if="otherPersonData.fullName?.length">
|
||||
{{ otherPersonData.fullName }}
|
||||
<span v-if="otherPersonData.fullNameWithTitle?.length">
|
||||
{{ otherPersonData.fullNameWithTitle }}
|
||||
<span @click.stop="copyFullNameWithTitleToClipboard()" :title="$p.t('LvPlan/copy')" class="fs-4 h-100">
|
||||
<i class="fa-regular fa-copy"></i>
|
||||
</span>
|
||||
</span>
|
||||
<img v-if="otherPersonData.photo?.length" alt="profile picture" class=" img-thumbnail " style=" max-height:60px; " :src="get_image_base64_src"/>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,7 @@ import RoleInformation from "./ProfilComponents/RoleInformation.js";
|
||||
import ProfilEmails from "./ProfilComponents/ProfilEmails.js";
|
||||
import ProfilInformation from "./ProfilComponents/ProfilInformation.js";
|
||||
import QuickLinks from "./ProfilComponents/QuickLinks.js";
|
||||
import ZeitsperrenUid from "../../Cis/ZeitsperrenMitarbeiter/Details/ZeitsperrenMitarbeiteruid.js";
|
||||
|
||||
import { dateFilter } from "../../../tabulator/filters/Dates.js";
|
||||
|
||||
@@ -15,6 +16,7 @@ export default {
|
||||
ProfilEmails,
|
||||
ProfilInformation,
|
||||
QuickLinks,
|
||||
ZeitsperrenUid
|
||||
},
|
||||
inject: ["collapseFunction", "language"],
|
||||
data() {
|
||||
@@ -216,8 +218,10 @@ export default {
|
||||
}
|
||||
return quickLinks;
|
||||
},
|
||||
stringTimelocks(){
|
||||
return `${this.$p.t("zeitsperren", "zeitsperrenVon")} ` + this.data.vorname + " " + this.data.nachname;
|
||||
}
|
||||
},
|
||||
|
||||
template: /*html*/ `
|
||||
|
||||
<div class="container-fluid text-break fhc-form" >
|
||||
@@ -285,6 +289,16 @@ export default {
|
||||
<quick-links :title="$p.t('profil/quickLinks')" :links="quickLinks" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- LINKS MITARBEITER -->
|
||||
<div class="card mb-2">
|
||||
<div class= "card-body">
|
||||
<zeitsperren-uid
|
||||
:maUid="data.username"
|
||||
:days="14"
|
||||
:title="stringTimelocks"
|
||||
></zeitsperren-uid>
|
||||
</div>
|
||||
</div>
|
||||
<!-- MAILVERTEILER -->
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
|
||||
@@ -67,6 +67,21 @@ export default {
|
||||
return res;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
copyFullNameWithTitleToClipboard() {
|
||||
let fragments = [
|
||||
this.$props.data.Titel,
|
||||
this.$props.data.Vorname,
|
||||
this.$props.data.Nachname,
|
||||
this.$props.data.Postnomen,
|
||||
];
|
||||
fragments = fragments.filter((fragment) => !!fragment);
|
||||
navigator.clipboard.writeText(fragments.join(" "));
|
||||
this.$fhcAlert.alertSuccess(
|
||||
this.$p.t("profil/name_title_clipboard_copy_confirmation"),
|
||||
);
|
||||
},
|
||||
},
|
||||
template: /*html*/ `
|
||||
|
||||
<div class="card h-100">
|
||||
@@ -124,6 +139,16 @@ export default {
|
||||
<span class="form-underline-content">{{wert?wert:'-'}} </span>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
@click="copyFullNameWithTitleToClipboard()"
|
||||
href="#"
|
||||
class="col-12 fhc-link-color d-flex flex-row gap-2 align-items-center justify-content-center mt-3"
|
||||
>
|
||||
<span>
|
||||
<i class="fa-regular fa-copy ms-2 text-decoration-none"></i>
|
||||
</span>
|
||||
<span>{{ $p.t("profil/name_title_copy") }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,676 @@
|
||||
import {CoreFilterCmpt} from "../../filter/Filter.js";
|
||||
import FormForm from '../../Form/Form.js';
|
||||
import FormInput from '../../Form/Input.js';
|
||||
import PvAutoComplete from '../../../../../index.ci.php/public/js/components/primevue/autocomplete/autocomplete.esm.min.js';
|
||||
|
||||
import ApiAuthinfo from '../../../api/factory/authinfo.js';
|
||||
import ApiTimelocks from "../../../api/factory/cis/zeitsperren.js";
|
||||
import ApiStvAbschlusspruefung from "../../../api/factory/stv/abschlusspruefung.js";
|
||||
|
||||
export default {
|
||||
name: 'ZeitsperrenComponent',
|
||||
components: {
|
||||
CoreFilterCmpt,
|
||||
FormForm,
|
||||
FormInput,
|
||||
PvAutoComplete
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
uid: null,
|
||||
statusNew: true,
|
||||
timeRecordingLockedUntil: '2015-08-31', //TODO(Manu) check if needed
|
||||
typesTimeLocks: ["Urlaub", "PflegeU", "ZA", "Krank", "DienstF", "DienstV", "CovidSB", "CovidKS"],
|
||||
typesHideStunden: ["Urlaub", "ZA", "Krank", "DienstF", "DienstV", "CovidSB", "CovidKS"],
|
||||
listTypenZeitsperren: [],
|
||||
listTypenErreichbarkeit: [],
|
||||
listStunden: [],
|
||||
tabulatorOptions: null,
|
||||
tabulatorEvents: [],
|
||||
originalData: {},
|
||||
zeitsperreData: {
|
||||
vondatum : new Date(),
|
||||
bisdatum: new Date(),
|
||||
vonISO : "00:00:00", //later
|
||||
bisISO: "23:59:59", //later
|
||||
erreichbarkeit_kurzbz: 'n',
|
||||
zeitsperretyp_kurzbz: 'Arzt',
|
||||
vonstunde: null,
|
||||
bisstunde: null
|
||||
},
|
||||
changedData: {},
|
||||
selectedVertretung: null,
|
||||
filteredMitarbeiter: [],
|
||||
abortController: {
|
||||
mitarbeiter: null
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
dienstverhinderungen() {
|
||||
return {
|
||||
"Eheschließung": "a) " + this.$p.t('zeitsperren', 'eheschliessung'),
|
||||
"Geburt eigenes Kind": "b) " + this.$p.t('zeitsperren', 'geburt'),
|
||||
"Heirat Kind/Geschwister": "c) " + this.$p.t('zeitsperren', 'heirat'),
|
||||
"Eigene Sponsion/Promotion": "d) " + this.$p.t('zeitsperren', 'sponsion'),
|
||||
"Lebensbedr. Erkrankung P/K/E": "e) " + this.$p.t('zeitsperren', 'erkrankung_lebensbedr'),
|
||||
"Ableben P/K/E": "f) " + this.$p.t('zeitsperren', 'ableben'),
|
||||
"Bestattung G/S/G": "g) " + this.$p.t('zeitsperren', 'bestattung'),
|
||||
"Wohnungswechsel": "h) " + this.$p.t('zeitsperren', 'umzug'),
|
||||
"Bundesheer": "i) " + this.$p.t('zeitsperren', 'bundesheer'),
|
||||
"Volksschultag": "j) " + this.$p.t('zeitsperren', 'volksschultag')};
|
||||
},
|
||||
showInfo(){
|
||||
return this.zeitsperreData.zeitsperretyp_kurzbz === 'DienstF';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
actionEditZeitsperre(zeitsperre_id){
|
||||
this.statusNew = false;
|
||||
return this.$api
|
||||
.call(ApiTimelocks.loadZeitsperre(zeitsperre_id))
|
||||
.then(response => {
|
||||
this.originalData = structuredClone(response.data);
|
||||
this.zeitsperreData = structuredClone(response.data);
|
||||
|
||||
this.selectedVertretung = {
|
||||
label: this.getPersonLabel(this.zeitsperreData.ma_titelpre, this.zeitsperreData.ma_nachname, this.zeitsperreData.ma_vorname, this.zeitsperreData.ma_titelpost, this.zeitsperreData.vertretung_uid),
|
||||
person_id: this.zeitsperreData.ma_person_id,
|
||||
mitarbeiter_uid: this.zeitsperreData.vertretung_uid
|
||||
};
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
actionDeleteZeitsperre(zeitsperre_id){
|
||||
this.$fhcAlert
|
||||
.confirmDelete()
|
||||
.then(result => result
|
||||
? zeitsperre_id
|
||||
: Promise.reject({ handled: true })
|
||||
)
|
||||
.then(() => this.deleteZeitsperre(zeitsperre_id))
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
saveZeitsperre(zeitsperreId = null) {
|
||||
const isNew = !zeitsperreId;
|
||||
|
||||
let payload = isNew
|
||||
? { ...this.zeitsperreData } // add
|
||||
: this.getChangedFields(this.originalData, // edit
|
||||
this.zeitsperreData);
|
||||
|
||||
if (!isNew && Object.keys(payload).length === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const request = isNew
|
||||
? ApiTimelocks.addZeitsperre(this.uid, payload)
|
||||
: ApiTimelocks.editZeitsperre(zeitsperreId, payload);
|
||||
|
||||
return this.$refs.dataZeitsperre
|
||||
.call(request)
|
||||
.then(() => {
|
||||
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave'));
|
||||
|
||||
this.reset();
|
||||
this.reload();
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
deleteZeitsperre(zeitsperre_id){
|
||||
return this.$api
|
||||
.call(ApiTimelocks.deleteZeitsperre(zeitsperre_id))
|
||||
.then(response => {
|
||||
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete'));
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError)
|
||||
.finally(()=> {
|
||||
this.reload();
|
||||
});
|
||||
},
|
||||
searchMitarbeiter(event) {
|
||||
if (this.abortController.mitarbeiter) {
|
||||
this.abortController.mitarbeiter.abort();
|
||||
}
|
||||
|
||||
this.abortController.mitarbeiter = new AbortController();
|
||||
|
||||
return this.$api
|
||||
.call(ApiStvAbschlusspruefung.getMitarbeiter(event.query))
|
||||
.then(result => {
|
||||
this.filteredMitarbeiter = [];
|
||||
for (let mitarbeiter of result.data.retval) {
|
||||
this.filteredMitarbeiter.push(
|
||||
{
|
||||
label: this.getPersonLabel(
|
||||
mitarbeiter.titelpre,
|
||||
mitarbeiter.nachname,
|
||||
mitarbeiter.vorname,
|
||||
mitarbeiter.titelpost,
|
||||
mitarbeiter.mitarbeiter_uid
|
||||
),
|
||||
person_id: mitarbeiter.person_id,
|
||||
mitarbeiter_uid: mitarbeiter.mitarbeiter_uid
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
getPersonLabel(titelpre, nachname, vorname, titelpost, uid) {
|
||||
if(!uid)
|
||||
return '';
|
||||
return nachname + ' ' + vorname + (titelpre ? ' ' + titelpre : '') + (titelpost ? ' ' + titelpost : '') + (uid ? ' (' + uid + ')' : '');
|
||||
},
|
||||
reload() {
|
||||
if (this.$refs.table)
|
||||
this.$refs.table.reloadTable();
|
||||
},
|
||||
reset(){
|
||||
this.statusNew = true;
|
||||
this.selectedVertretung = null;
|
||||
this.zeitsperreData = {
|
||||
vondatum : new Date(),
|
||||
bisdatum: new Date(),
|
||||
vonISO : "00:00:00", //later
|
||||
bisISO: "23:59:59", //later
|
||||
erreichbarkeit_kurzbz: 'n',
|
||||
zeitsperretyp_kurzbz: 'Arzt',
|
||||
vonstunde: null,
|
||||
bisstunde: null
|
||||
};
|
||||
this.originalData = {};
|
||||
},
|
||||
handleChangeVonStunde(){
|
||||
let stunde = this.zeitsperreData.vonstunde;
|
||||
const result = this.listStunden.find(item => item.stunde === stunde);
|
||||
if (!result) {
|
||||
this.zeitsperreData.vonISO = '00:00:00';
|
||||
return;
|
||||
}
|
||||
this.zeitsperreData.vonISO = result.beginn;
|
||||
},
|
||||
handleChangeBisStunde(){
|
||||
let stunde = this.zeitsperreData.bisstunde;
|
||||
const result = this.listStunden.find(item => item.stunde === stunde);
|
||||
if (!result) {
|
||||
this.zeitsperreData.bisISO = '23:59:59';
|
||||
return;
|
||||
}
|
||||
this.zeitsperreData.bisISO = result.ende;
|
||||
},
|
||||
handleStunden(){
|
||||
if (this.typesHideStunden.includes(this.zeitsperreData.zeitsperretyp_kurzbz)){
|
||||
this.zeitsperreData.vonstunde = null;
|
||||
this.zeitsperreData.bisstunde = null;
|
||||
this.zeitsperreData.vonISO = '00:00:00';
|
||||
this.zeitsperreData.bisISO = '23:59:59';
|
||||
}
|
||||
},
|
||||
copyDateForBis(){
|
||||
this.zeitsperreData.bisdatum = this.zeitsperreData.vondatum;
|
||||
},
|
||||
getChangedFields(original, current) {
|
||||
const diff = {};
|
||||
|
||||
Object.keys(current).forEach((key) => {
|
||||
if (current[key] !== original[key]) {
|
||||
diff[key] = current[key];
|
||||
}
|
||||
});
|
||||
return diff;
|
||||
},
|
||||
async updateTableTranslations() {
|
||||
await this.$p.loadCategory(['global', 'person', 'zeitsperren', 'ui', 'abschlusspruefung']);
|
||||
|
||||
let cm = this.$refs.table.tabulator.columnManager;
|
||||
|
||||
cm.getColumnByField('bezeichnung').component.updateDefinition({
|
||||
title: this.$capitalize(this.$p.t('person', 'grund'))
|
||||
});
|
||||
cm.getColumnByField('beschreibung').component.updateDefinition({
|
||||
title: this.$capitalize(this.$p.t('global', 'bezeichnung'))
|
||||
});
|
||||
cm.getColumnByField('vondatum').component.updateDefinition({
|
||||
title: this.$capitalize(this.$p.t('ui', 'von'))
|
||||
});
|
||||
cm.getColumnByField('bisdatum').component.updateDefinition({
|
||||
title: this.$capitalize(this.$p.t('global', 'bis'))
|
||||
});
|
||||
cm.getColumnByField('vonstunde').component.updateDefinition({
|
||||
title: this.$capitalize(this.$p.t('zeitsperren', 'stunde_von'))
|
||||
});
|
||||
cm.getColumnByField('bisstunde').component.updateDefinition({
|
||||
title: this.$capitalize(this.$p.t('zeitsperren', 'stunde_bis'))
|
||||
});
|
||||
cm.getColumnByField('vertretung').component.updateDefinition({
|
||||
title: this.$capitalize(this.$p.t('person', 'vertretung'))
|
||||
});
|
||||
cm.getColumnByField('erreichbarkeit_beschreibung').component.updateDefinition({
|
||||
title: this.$capitalize(this.$p.t('person', 'erreichbarkeit'))
|
||||
});
|
||||
cm.getColumnByField('freigabeamum').component.updateDefinition({
|
||||
title: this.$capitalize(this.$p.t('abschlusspruefung', 'freigabe'))
|
||||
});
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
selectedVertretung(newVal) {
|
||||
this.zeitsperreData.vertretung_uid = newVal?.mitarbeiter_uid || null;
|
||||
},
|
||||
'zeitsperreData.zeitsperretyp_kurzbz'(newVal) {
|
||||
if (newVal === 'DienstV') {
|
||||
// set first key as default
|
||||
if (!this.zeitsperreData.bezeichnung) {
|
||||
const firstKey = Object.keys(this.dienstverhinderungen)[0];
|
||||
this.zeitsperreData.bezeichnung = firstKey;
|
||||
}
|
||||
} else {
|
||||
this.zeitsperreData.bezeichnung = '';
|
||||
}
|
||||
},
|
||||
'$p.user_language.value'(n, o) {
|
||||
if (n !== o && o !== undefined && this.$refs.table.tableBuilt) {
|
||||
this.updateTableTranslations();
|
||||
this.reload();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$api.call(ApiAuthinfo.getAuthUID()).then(res => {
|
||||
|
||||
//check if there is a user, passed via route
|
||||
const urlUid = this.$route?.query?.uid;
|
||||
this.uid = urlUid ? urlUid : res.data.uid;
|
||||
|
||||
this.tabulatorOptions = {
|
||||
ajaxURL: 'dummy',
|
||||
ajaxRequestFunc: () =>
|
||||
this.$api.call(ApiTimelocks.getTimelocksUser(this.uid)),
|
||||
ajaxResponse: (url, params, response) => response.data,
|
||||
columns: [
|
||||
{title:"bezeichnung", field:"bezeichnung"},
|
||||
{title:"Grund", field:"beschreibung"},
|
||||
{title:"Von", field:"vondatum",
|
||||
formatter: function (cell) {
|
||||
const dateStr = cell.getValue();
|
||||
if (!dateStr) return "";
|
||||
|
||||
const date = new Date(dateStr);
|
||||
return date.toLocaleString("de-DE", {
|
||||
day: "2-digit",
|
||||
month: "2-digit",
|
||||
year: "numeric",
|
||||
});
|
||||
}
|
||||
},
|
||||
{title:"Bis", field:"bisdatum",
|
||||
formatter: function (cell) {
|
||||
const dateStr = cell.getValue();
|
||||
if (!dateStr) return "";
|
||||
|
||||
const date = new Date(dateStr);
|
||||
return date.toLocaleString("de-DE", {
|
||||
day: "2-digit",
|
||||
month: "2-digit",
|
||||
year: "numeric",
|
||||
});
|
||||
}
|
||||
},
|
||||
{title:"vonstunde", field:"vonstunde", visible: false},
|
||||
{title:"bisstunde", field:"bisstunde", visible: false},
|
||||
{title:"Vertretung", field:"vertretung"},
|
||||
{title:"Erreichbarkeit", field:"erreichbarkeit_beschreibung"},
|
||||
{title:"zeitsperre_id", field:"zeitsperre_id", visible: false},
|
||||
{title:"mitarbeiter_uid", field:"mitarbeiter_uid", visible: false},
|
||||
{title:"freigabeamum", field:"freigabeamum", visible: false,
|
||||
formatter: function (cell) {
|
||||
const value = cell.getValue();
|
||||
return value === null
|
||||
? ''
|
||||
: '<i class="fa fa-check text-success"></i>';
|
||||
}
|
||||
},
|
||||
{title: 'Aktionen', field: 'actions',
|
||||
minWidth: 150, // Ensures Action-buttons will be always fully displayed
|
||||
formatter: (cell, formatterParams, onRendered) => {
|
||||
let container = document.createElement('div');
|
||||
container.className = "d-flex gap-2";
|
||||
|
||||
let button = document.createElement('button');
|
||||
button.className = 'btn btn-outline-secondary btn-action';
|
||||
button.innerHTML = '<i class="fa fa-edit"></i>';
|
||||
button.title = this.$p.t('ui', 'bearbeiten');
|
||||
button.addEventListener('click', (event) =>
|
||||
this.actionEditZeitsperre(cell.getData().zeitsperre_id)
|
||||
);
|
||||
if(cell.getData().zeitsperretyp_kurzbz == 'DienstV' || cell.getData().zeitsperretyp_kurzbz == 'ZVerfueg'){
|
||||
button.disabled = true;
|
||||
}
|
||||
//TODO(Manu) check if needed
|
||||
if(this.typesTimeLocks.includes(cell.getData().zeitsperretyp_kurzbz) && (cell.getData().vondatum < this.timeRecordingLockedUntil)){
|
||||
button.disabled = true;
|
||||
}
|
||||
container.append(button);
|
||||
|
||||
button = document.createElement('button');
|
||||
button.className = 'btn btn-outline-secondary btn-action';
|
||||
button.innerHTML = '<i class="fa fa-xmark"></i>';
|
||||
button.title = this.$p.t('ui', 'loeschen');
|
||||
button.addEventListener('click', () =>
|
||||
//this.deleteZeitsperre(cell.getData().zeitsperre_id)
|
||||
this.actionDeleteZeitsperre(cell.getData().zeitsperre_id)
|
||||
);
|
||||
if(cell.getData().zeitsperretyp_kurzbz == 'Urlaub' || cell.getData().zeitsperretyp_kurzbz == 'ZVerfueg'){
|
||||
button.disabled = true;
|
||||
}
|
||||
//TODO(Manu) check if needed
|
||||
if(this.typesTimeLocks.includes(cell.getData().zeitsperretyp_kurzbz) && (cell.getData().vondatum < this.timeRecordingLockedUntil)){
|
||||
button.disabled = true;
|
||||
}
|
||||
container.append(button);
|
||||
|
||||
return container;
|
||||
},
|
||||
frozen: true
|
||||
},
|
||||
]
|
||||
};
|
||||
this.tabulatorEvents = [
|
||||
{
|
||||
event: 'tableBuilt',
|
||||
handler: async() => {
|
||||
await this.updateTableTranslations();
|
||||
}
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
this.$api
|
||||
.call(ApiTimelocks.getTypenZeitsperren())
|
||||
.then(result => {
|
||||
this.listTypenZeitsperren = result.data;
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
|
||||
this.$api
|
||||
.call(ApiTimelocks.getTypenErreichbarkeit())
|
||||
.then(result => {
|
||||
this.listTypenErreichbarkeit = result.data;
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
|
||||
this.$api
|
||||
.call(ApiTimelocks.getStunden())
|
||||
.then(result => {
|
||||
this.listStunden = result.data;
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
|
||||
},
|
||||
template: /* html */`
|
||||
<div class="zeitsperre">
|
||||
<h4>{{$p.t('zeitsperren', 'header_zeitsperren')}} ({{uid}})</h4>
|
||||
|
||||
<form-form class="row g-3 mt-3" ref="dataZeitsperre">
|
||||
<div class= "w-50">
|
||||
<div class="row mb-3">
|
||||
<form-input
|
||||
type="select"
|
||||
:class="showInfo ? 'is-info' : ''"
|
||||
name="zeitsperretyp_kurzbz"
|
||||
:label="$capitalize($p.t('person/grund'))"
|
||||
v-model="zeitsperreData.zeitsperretyp_kurzbz"
|
||||
@change="handleStunden"
|
||||
>
|
||||
<option
|
||||
v-for="typ in listTypenZeitsperren"
|
||||
:key="typ.zeitsperretyp_kurzbz"
|
||||
:value="typ.zeitsperretyp_kurzbz"
|
||||
:disabled="typ.zeitsperretyp_kurzbz == 'Urlaub'"
|
||||
>
|
||||
{{typ.beschreibung}}
|
||||
</option>
|
||||
</form-input>
|
||||
<div v-if="showInfo" class="info-feedback">
|
||||
<strong> Dienstfreistellungen</strong> nur in Absprache mit HR Service eintragen!
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="zeitsperreData.zeitsperretyp_kurzbz == 'DienstV'" class="row mb-3">
|
||||
<form-input
|
||||
type="select"
|
||||
name="beschreibung"
|
||||
:label="$capitalize($p.t('ui/bezeichnung'))"
|
||||
v-model="zeitsperreData.bezeichnung"
|
||||
>
|
||||
<option v-for="(beschreibung, key) in dienstverhinderungen"
|
||||
:key="key"
|
||||
:value="key">{{beschreibung}}
|
||||
</option>
|
||||
|
||||
</form-input>
|
||||
</div>
|
||||
<div v-else class="row mb-3">
|
||||
<form-input
|
||||
type="text"
|
||||
name="beschreibung"
|
||||
:label="$capitalize($p.t('ui/bezeichnung'))"
|
||||
v-model="zeitsperreData.bezeichnung"
|
||||
>
|
||||
</form-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="mb-3 col-2">
|
||||
<form-input
|
||||
type="DatePicker"
|
||||
name="vondatum"
|
||||
:label="$capitalize($p.t('ui/from'))"
|
||||
v-model="zeitsperreData.vondatum"
|
||||
auto-apply
|
||||
:enable-time-picker="false"
|
||||
format="dd.MM.yyyy"
|
||||
text-input
|
||||
preview-format="dd.MM.yyyy"
|
||||
:teleport="true"
|
||||
required
|
||||
>
|
||||
</form-input>
|
||||
</div>
|
||||
<div class="mb-3 col-1 d-flex align-items-end">
|
||||
<button
|
||||
class="btn btn-outline-secondary"
|
||||
title="Für Bis-Datum übernehmen"
|
||||
@click.prevent="copyDateForBis"
|
||||
>
|
||||
<i class="fa-solid fa-arrow-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 col-3">
|
||||
<form-input
|
||||
v-if="!typesHideStunden.includes(zeitsperreData.zeitsperretyp_kurzbz)"
|
||||
type="select"
|
||||
name="vonstunde"
|
||||
:label="$capitalize($p.t('zeitsperren/stunde'))"
|
||||
v-model="zeitsperreData.vonstunde"
|
||||
@change="handleChangeVonStunde"
|
||||
>
|
||||
<option value='null'>*</option>
|
||||
<option
|
||||
v-for="std in listStunden"
|
||||
:key="std.stunde"
|
||||
:value="std.stunde"
|
||||
>
|
||||
{{std.stunde}} ({{std.beginn}} - {{std.ende}})
|
||||
</option>
|
||||
</form-input>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Uncomment to use timestamp VON
|
||||
<div class="mb-3 col-3">
|
||||
<form-input
|
||||
type="text"
|
||||
name="vonISO"
|
||||
label="vonISO"
|
||||
v-model="zeitsperreData.vonISO"
|
||||
auto-apply
|
||||
:enable-time-picker="true"
|
||||
format="dd.MM.yyyy HH:mm"
|
||||
text-input
|
||||
preview-format="dd.MM.yyyy HH:mm"
|
||||
:teleport="true"
|
||||
>
|
||||
{{timestampHoursVon}}
|
||||
</form-input>
|
||||
</div>
|
||||
-->
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="mb-3 col-2">
|
||||
<form-input
|
||||
type="DatePicker"
|
||||
name="bisdatum"
|
||||
:label="$capitalize($p.t('global/bis'))"
|
||||
v-model="zeitsperreData.bisdatum"
|
||||
auto-apply
|
||||
:enable-time-picker="false"
|
||||
format="dd.MM.yyyy"
|
||||
text-input
|
||||
preview-format="dd.MM.yyyy"
|
||||
:teleport="true"
|
||||
required
|
||||
>
|
||||
</form-input>
|
||||
</div>
|
||||
<div class="mb-3 col-1"></div>
|
||||
|
||||
<div class="mb-3 col-3">
|
||||
<form-input
|
||||
v-if="!typesHideStunden.includes(zeitsperreData.zeitsperretyp_kurzbz)"
|
||||
type="select"
|
||||
name="bisstunde"
|
||||
:label="$capitalize($p.t('zeitsperren/stunde'))"
|
||||
v-model="zeitsperreData.bisstunde"
|
||||
@change="handleChangeBisStunde"
|
||||
>
|
||||
<option value='null'>*</option>
|
||||
<option
|
||||
v-for="std in listStunden"
|
||||
:key="std.stunde"
|
||||
:value="std.stunde"
|
||||
>
|
||||
{{std.stunde}} ({{std.beginn}} - {{std.ende}})
|
||||
</option>
|
||||
</form-input>
|
||||
</div>
|
||||
|
||||
<!-- Uncomment to use timestamp BIS
|
||||
<div class="mb-3 col-3">
|
||||
<form-input
|
||||
type="text"
|
||||
name="bisISO"
|
||||
label="bisISO"
|
||||
v-model="zeitsperreData.bisISO"
|
||||
auto-apply
|
||||
:enable-time-picker="true"
|
||||
format="dd.MM.yyyy HH:mm"
|
||||
text-input
|
||||
preview-format="dd.MM.yyyy HH:mm"
|
||||
:teleport="true"
|
||||
>
|
||||
</form-input>
|
||||
</div>
|
||||
-->
|
||||
|
||||
</div>
|
||||
|
||||
<div class= "w-50">
|
||||
<div class="row mb-3">
|
||||
<form-input
|
||||
type="autocomplete"
|
||||
name="vertretung_uid"
|
||||
:label="$capitalize($p.t('person/vertretung'))"
|
||||
v-model="selectedVertretung"
|
||||
optionLabel="label"
|
||||
optionValue="mitarbeiter_uid"
|
||||
dropdown
|
||||
forceSelection
|
||||
:suggestions="filteredMitarbeiter"
|
||||
@complete="searchMitarbeiter"
|
||||
:min-length="3"
|
||||
>
|
||||
</form-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row align-items-end">
|
||||
<div class="mb-3 col-4">
|
||||
<form-input
|
||||
type="select"
|
||||
name="erreichbarkeit"
|
||||
:label="$capitalize($p.t('person/erreichbarkeit'))"
|
||||
v-model="zeitsperreData.erreichbarkeit_kurzbz"
|
||||
>
|
||||
<option
|
||||
v-for="typ in listTypenErreichbarkeit"
|
||||
:key="typ.erreichbarkeit_kurzbz"
|
||||
:value="typ.erreichbarkeit_kurzbz"
|
||||
>
|
||||
{{typ.beschreibung}}
|
||||
</option>
|
||||
</form-input>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 col-3">
|
||||
<button
|
||||
v-if="statusNew"
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
@click="saveZeitsperre()">
|
||||
{{$capitalize($p.t('zeitsperren', 'addZeitsperre'))}}
|
||||
</button>
|
||||
<button
|
||||
v-else
|
||||
type="button"
|
||||
class="btn btn-warning"
|
||||
@click="saveZeitsperre(zeitsperreData.zeitsperre_id)">
|
||||
{{$capitalize($p.t('zeitsperren', 'saveZeitsperre'))}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</form-form>
|
||||
|
||||
<div class="d-flex align-items-start text-muted small">
|
||||
<i class="fa fa-circle-info me-2 mt-1"></i>
|
||||
<div>
|
||||
<strong>{{$capitalize($p.t('alert', 'attention'))}}</strong><br>
|
||||
{{$p.t('zeitsperren', 'info_zeitsperrenMoreDays')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<core-filter-cmpt
|
||||
v-if="tabulatorOptions"
|
||||
ref="table"
|
||||
:tabulator-options="tabulatorOptions"
|
||||
:tabulator-events="tabulatorEvents"
|
||||
table-only
|
||||
:side-menu="false"
|
||||
reload
|
||||
:reload-btn-infotext="this.$p.t('table', 'reload')"
|
||||
>
|
||||
</core-filter-cmpt>
|
||||
</div>
|
||||
`
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
export default {
|
||||
name: "timelocksMitarbeiteruid",
|
||||
props: {
|
||||
maUid: {
|
||||
type: String
|
||||
},
|
||||
days: {
|
||||
type: Number
|
||||
},
|
||||
title: {
|
||||
type: String
|
||||
}
|
||||
|
||||
},
|
||||
methods: {
|
||||
link(maUid, days){
|
||||
this.$router.push({
|
||||
name: 'ZeitsperrenMa',
|
||||
params: {
|
||||
type: 'ma',
|
||||
id: maUid,
|
||||
days: days
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<a href="#" @click.prevent="link(maUid, days)">
|
||||
{{title}}
|
||||
</a>
|
||||
</div>
|
||||
`,
|
||||
}
|
||||
@@ -0,0 +1,582 @@
|
||||
import {CoreFilterCmpt} from "../../../filter/Filter.js";
|
||||
import ApiMaTimelocks from "../../../../api/factory/zeitsperren.js";
|
||||
import FormForm from "../../../Form/Form.js";
|
||||
import FormInput from "../../../Form/Input.js";
|
||||
import PvAutoComplete from "../../../../../../index.ci.php/public/js/components/primevue/autocomplete/autocomplete.esm.min.js";
|
||||
|
||||
export default {
|
||||
name: "listsTimelocks",
|
||||
components: {
|
||||
FormForm,
|
||||
FormInput,
|
||||
PvAutoComplete,
|
||||
CoreFilterCmpt
|
||||
},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'all',
|
||||
validator(value) {
|
||||
return [
|
||||
'all',
|
||||
'fix',
|
||||
'lector',
|
||||
'oe',
|
||||
'ass',
|
||||
'stg',
|
||||
'ma'
|
||||
].includes(value)
|
||||
}
|
||||
},
|
||||
tage: {
|
||||
type: String
|
||||
},
|
||||
id: {
|
||||
type: String
|
||||
},
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
interval: 14,
|
||||
days: {},
|
||||
arrayMaTimelocks: [],
|
||||
listOes: [],
|
||||
filteredOes: [],
|
||||
selectedOe: null,
|
||||
oe_kurzbz: null,
|
||||
listStg: [],
|
||||
filteredStg: [],
|
||||
selectedStg: null,
|
||||
studiengang_kz: null,
|
||||
showTable: true,
|
||||
fullName: null,
|
||||
maUid: null,
|
||||
validStgs: [],
|
||||
validOes: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loadAllActiveZeitsperren(days){
|
||||
this.$api
|
||||
.call(ApiMaTimelocks.loadAllActiveZeitsperren(days))
|
||||
.then(result => {
|
||||
this.arrayMaTimelocks = result.data;
|
||||
})
|
||||
},
|
||||
loadZeitsperrenFixeMa(days){
|
||||
this.$api
|
||||
.call(ApiMaTimelocks.loadAllZeitsperrenFixeMa(days))
|
||||
.then(result => {
|
||||
this.arrayMaTimelocks = result.data;
|
||||
})
|
||||
},
|
||||
loadZeitsperrenLector(days){
|
||||
this.$api
|
||||
.call(ApiMaTimelocks.loadAllZeitsperrenLector(days))
|
||||
.then(result => {
|
||||
this.arrayMaTimelocks = result.data;
|
||||
})
|
||||
},
|
||||
loadZeitsperrenOE(days, oe){
|
||||
this.$router.push({
|
||||
name: 'ZeitsperrenMa',
|
||||
params: {
|
||||
type: this.$route.params.type,
|
||||
id: oe,
|
||||
days: days
|
||||
}
|
||||
});
|
||||
this.$api
|
||||
.call(ApiMaTimelocks.loadAllZeitsperrenOE(days, oe))
|
||||
.then(result => {
|
||||
this.arrayMaTimelocks = result.data;
|
||||
})
|
||||
},
|
||||
loadZeitsperrenAss(days){
|
||||
this.$api
|
||||
.call(ApiMaTimelocks.loadZeitsperrenAss(days))
|
||||
.then(result => {
|
||||
this.arrayMaTimelocks = result.data;
|
||||
})
|
||||
},
|
||||
loadZeitsperrenStg(days, stg){
|
||||
this.$router.push({
|
||||
name: 'ZeitsperrenMa',
|
||||
params: {
|
||||
type: this.$route.params.type,
|
||||
id: stg,
|
||||
days: days
|
||||
}
|
||||
});
|
||||
this.$api
|
||||
.call(ApiMaTimelocks.loadZeitsperrenLectorStg(days, stg))
|
||||
.then(result => {
|
||||
this.arrayMaTimelocks = result.data;
|
||||
})
|
||||
},
|
||||
loadZeitsperrenMa(days, uid){
|
||||
this.$api
|
||||
.call(ApiMaTimelocks.loadZeitsperrenMa(days, uid))
|
||||
.then(result => {
|
||||
this.arrayMaTimelocks = result.data;
|
||||
})
|
||||
},
|
||||
createDays(countDays) {
|
||||
const today = new Date();
|
||||
//get Monday before today
|
||||
const mondayBeforeToday = new Date(today);
|
||||
const day = today.getDay();
|
||||
const diff = day === 0 ? 6 : day - 1;
|
||||
|
||||
mondayBeforeToday.setDate(today.getDate() - diff);
|
||||
|
||||
this.days = Array.from({ length: countDays + 1 }, (_, i) => {
|
||||
const date = new Date(mondayBeforeToday);
|
||||
date.setDate(mondayBeforeToday.getDate() + i);
|
||||
|
||||
return {
|
||||
date: date.toISOString().substring(0, 10), // 2026-07-13
|
||||
weekday: date.toLocaleDateString('de-AT', { weekday: 'short' }),
|
||||
day: date.toLocaleDateString('de-AT', {
|
||||
day: '2-digit',
|
||||
month: '2-digit'
|
||||
})
|
||||
};
|
||||
});
|
||||
},
|
||||
createArrayMa(type){
|
||||
this.showTable = true;
|
||||
if(type == "fix") {
|
||||
if(this.id && this.isZifferString(this.id))
|
||||
this.interval = Number(this.id) < 100 ? Number(this.id) : this.interval;
|
||||
|
||||
this.loadZeitsperrenFixeMa(this.interval);
|
||||
}
|
||||
else if(type == "lector") {
|
||||
if(this.id && this.isZifferString(this.id))
|
||||
this.interval = Number(this.id) < 100 ? Number(this.id) : this.interval;
|
||||
this.loadZeitsperrenLector(this.interval);
|
||||
}
|
||||
else if(type == "oe") {
|
||||
this.loadOes().then(() => {
|
||||
if(this.id && this.validOes.includes(this.id)) {
|
||||
const countDays = this.tage ? Number(this.tage) : this.interval;
|
||||
|
||||
this.oe_temp = this.listOes.filter(
|
||||
item => item.oe_kurzbz === this.id
|
||||
);
|
||||
this.selectedOe = this.oe_temp[0];
|
||||
|
||||
this.loadZeitsperrenOE(
|
||||
countDays,
|
||||
this.selectedOe.oe_kurzbz
|
||||
);
|
||||
} else {
|
||||
if(this.id)
|
||||
this.interval = Number(this.id) < 100
|
||||
? Number(this.id)
|
||||
: this.interval;
|
||||
|
||||
this.showTable = false;
|
||||
this.selectedOe = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
else if(type == "stg") {
|
||||
this.loadStgs().then(() => {
|
||||
if(this.id && this.validStgs.includes(Number(this.id)))
|
||||
{
|
||||
const countDays= this.tage ? Number(this.tage) : this.interval;
|
||||
this.stg_temp = this.listStg.filter(
|
||||
item => item.studiengang_kz === Number(this.id)
|
||||
);
|
||||
this.selectedStg = this.stg_temp[0];
|
||||
this.loadZeitsperrenStg(countDays, this.id)
|
||||
}
|
||||
else
|
||||
{
|
||||
if(this.id && this.isZifferString(this.id))
|
||||
this.interval = Number(this.id) < 100 ? Number(this.id) : this.interval;
|
||||
this.showTable = false;
|
||||
this.selectedStg = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
else if(type == "all") {
|
||||
if(this.id && this.isZifferString(this.id))
|
||||
this.interval = Number(this.id) < 100 ? Number(this.id) : this.interval;
|
||||
this.loadAllActiveZeitsperren(this.interval);
|
||||
}
|
||||
else if(type == "ass") {
|
||||
if(this.id && this.isZifferString(this.id))
|
||||
this.interval = Number(this.id) < 100 ? Number(this.id) : this.interval;
|
||||
this.loadZeitsperrenAss(this.interval);
|
||||
}
|
||||
else if(type == "ma") {
|
||||
if(!this.id)
|
||||
this.$fhcAlert.alertError(this.$p.t('ui', 'error_missingId', {id: "mitarbeiteruid"}));
|
||||
const countDays= this.tage ? this.tage : this.interval;
|
||||
this.loadZeitsperrenMa(countDays, this.id);
|
||||
this.loadDetailsMa(this.id);
|
||||
}
|
||||
else
|
||||
{
|
||||
//route back if no type found
|
||||
this.$router.push({
|
||||
name: 'ZeitsperrenMa',
|
||||
});
|
||||
}
|
||||
},
|
||||
isBlocked(mitarbeiter, tag) {
|
||||
if (!mitarbeiter?.sperren) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mitarbeiter.sperren.some(s =>
|
||||
tag >= s.vondatum &&
|
||||
tag <= s.bisdatum
|
||||
);
|
||||
},
|
||||
getSperre(mitarbeiter, tag){
|
||||
return mitarbeiter.sperren.find(s =>
|
||||
tag >= s.vondatum &&
|
||||
tag <= s.bisdatum
|
||||
);
|
||||
},
|
||||
limitDays(event) {
|
||||
let value = event.target.value.replace(/\D/g, '').slice(0, 2);
|
||||
event.target.value = value;
|
||||
this.interval = value ? Number(value) : null;
|
||||
},
|
||||
filterOes(event) {
|
||||
const query = event.query.toLowerCase();
|
||||
|
||||
this.filteredOes = this.listOes.filter(item =>
|
||||
item.label.toLowerCase().includes(query)
|
||||
);
|
||||
},
|
||||
filterStg(event) {
|
||||
const query = event.query.toLowerCase();
|
||||
|
||||
this.filteredStg = this.listStg.filter(item =>
|
||||
item.label.toLowerCase().includes(query)
|
||||
);
|
||||
},
|
||||
link(uid) {
|
||||
return (
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
"/Cis/Profil/View/"+
|
||||
uid
|
||||
);
|
||||
},
|
||||
loadDetailsMa(uid){
|
||||
if(!uid)
|
||||
this.$fhcAlert.alertError(this.$p.t('ui', 'error_fieldNotFound', {field: "UID Mitarbeiter"}));
|
||||
|
||||
this.$api
|
||||
.call(ApiMaTimelocks.getDetailsMa(uid))
|
||||
.then(result => {
|
||||
this.fullName = result.data;
|
||||
})
|
||||
},
|
||||
isZifferString(wert) {
|
||||
//to check if the wert of the route param is a ziffer or a real String
|
||||
return typeof wert === 'string' && wert.trim() !== '' && !isNaN(wert);
|
||||
},
|
||||
async loadOes() {
|
||||
try {
|
||||
const result = await this.$api.call(ApiMaTimelocks.getAllOes());
|
||||
this.listOes = result.data.filter(item => item.aktiv);
|
||||
this.validOes = this.listOes.map(item => item.oe_kurzbz);
|
||||
} catch (e) {
|
||||
this.$fhcAlert.handleSystemError(e);
|
||||
}
|
||||
return this.validOes;
|
||||
},
|
||||
async loadStgs() {
|
||||
try {
|
||||
const result = await this.$api.call(ApiMaTimelocks.getAllStg());
|
||||
this.listStg = result.data;
|
||||
this.validStgs = this.listStg.map(item => item.studiengang_kz);
|
||||
} catch (e) {
|
||||
this.$fhcAlert.handleSystemError(e);
|
||||
}
|
||||
return this.validOes;
|
||||
},
|
||||
checkRoute(){
|
||||
if (this.type === 'ma' && !this.id) {
|
||||
//const errorString = this.$p.t('ui', 'successSave');
|
||||
const errorString = "Keine ID für Mitarbeiter übergeben";
|
||||
return errorString;
|
||||
}
|
||||
if (this.type === 'stg' && !this.isZifferString(this.id)) {
|
||||
//const errorString = this.$p.t('ui', 'successSave');
|
||||
const errorString = "Studiengangskennzahl darf nur aus Zahlen bestehen";
|
||||
return errorString;
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
today(){
|
||||
const today = new Date();
|
||||
const day = today.toLocaleDateString('de-AT', {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric'
|
||||
});
|
||||
return day;
|
||||
},
|
||||
mondayBeforeToday(){
|
||||
const today = new Date();
|
||||
//get Monday before today
|
||||
const mondayBeforeToday = new Date(today);
|
||||
const day = today.getDay();
|
||||
const diff = day === 0 ? 6 : day - 1;
|
||||
|
||||
mondayBeforeToday.setDate(today.getDate() - diff);
|
||||
|
||||
return mondayBeforeToday;
|
||||
},
|
||||
endInterval(){
|
||||
const today = new Date();
|
||||
const end = new Date(this.mondayBeforeToday);
|
||||
end.setDate(end.getDate() + this.interval);
|
||||
|
||||
return end.toLocaleDateString('de-AT', {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric'
|
||||
});
|
||||
},
|
||||
mitarbeiter() {
|
||||
const map = {};
|
||||
|
||||
this.arrayMaTimelocks.forEach(z => {
|
||||
if (!map[z.uid]) {
|
||||
map[z.uid] = [];
|
||||
}
|
||||
|
||||
map[z.uid].push(z);
|
||||
});
|
||||
|
||||
return Object.entries(map).map(([mitarbeiter_uid, sperren]) => ({
|
||||
mitarbeiter_uid,
|
||||
sperren
|
||||
}));
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
interval: {
|
||||
handler(newVal) {
|
||||
if (newVal) {
|
||||
if(this.type == "fix") {
|
||||
this.loadZeitsperrenFixeMa(newVal);
|
||||
}
|
||||
else if(this.type == "lector") {
|
||||
this.loadZeitsperrenLector(newVal);
|
||||
}
|
||||
else if(this.type == "oe") {
|
||||
if(this.oe_kurzbz && this.oe_kurzbz !="")
|
||||
this.loadZeitsperrenOE(newVal, this.oe_kurzbz);
|
||||
}
|
||||
else if(this.type == "all")
|
||||
{
|
||||
this.loadAllActiveZeitsperren(newVal);
|
||||
}
|
||||
else if(this.type == "ass") {
|
||||
this.loadZeitsperrenAss(newVal);
|
||||
}
|
||||
else if(this.type == "stg") {
|
||||
if(this.selectedStg )
|
||||
this.loadZeitsperrenStg(newVal, this.studiengang_kz);
|
||||
}
|
||||
else if(this.type == "ma") {
|
||||
this.loadZeitsperrenMa(newVal, this.maUid);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.$fhcAlert.alertError(this.$p.t('ui', 'error_fieldNotFound', {field: "Typ Zeitsperre"}));
|
||||
}
|
||||
this.createDays(newVal);
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
selectedOe(newVal) {
|
||||
this.oe_kurzbz = newVal?.oe_kurzbz || '';
|
||||
},
|
||||
oe_kurzbz(newVal){
|
||||
{
|
||||
if(newVal != "") {
|
||||
this.loadZeitsperrenOE(this.interval, newVal);
|
||||
this.showTable = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
selectedStg(newVal) {
|
||||
this.studiengang_kz = newVal?.studiengang_kz || '';
|
||||
},
|
||||
studiengang_kz(newVal){
|
||||
{
|
||||
if(newVal != "") {
|
||||
this.loadZeitsperrenStg(this.interval, newVal);
|
||||
this.showTable = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
type(newVal){
|
||||
{
|
||||
if(newVal != "")
|
||||
this.createArrayMa(newVal);
|
||||
}
|
||||
},
|
||||
},
|
||||
created(){
|
||||
const error = this.checkRoute();
|
||||
if (error) {
|
||||
console.log(error);
|
||||
this.$fhcAlert.alertError(error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.createArrayMa(this.type);
|
||||
if(this.tage && Number(this.tage) < 100) {
|
||||
this.createDays(Number(this.tage));
|
||||
this.interval = Number(this.tage);
|
||||
}
|
||||
else
|
||||
this.createDays(this.interval);
|
||||
|
||||
if (this.type === 'oe') {
|
||||
this.oe_kurzbz = this.id
|
||||
} else if (this.type === 'stg'){
|
||||
this.studiengang_kz = this.id;
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="zeitsperrenma-container">
|
||||
|
||||
<!-- header-->
|
||||
<div class="zeitsperrenma-header">
|
||||
<h4 class="mt-3"><span v-if="type=='all'">{{$p.t('zeitsperren/title_allMa')}}</span>
|
||||
<span v-if="type=='fix'">{{$p.t('zeitsperren/title_fix')}}</span>
|
||||
<span v-if="type=='lector'">{{$p.t('zeitsperren/title_fixLecturers')}}</span>
|
||||
<span v-if="type=='oe'">{{$p.t('zeitsperren/title_byOe')}}</span>
|
||||
<span v-if="type=='stg'">{{$p.t('zeitsperren/title_lectStg')}}</span>
|
||||
<span v-if="type=='ass'">{{$p.t('zeitsperren/title_ass')}}</span>
|
||||
<span v-if="type=='ma'">{{$p.t('zeitsperren/zeitsperrenVon')}} {{fullName}}</span>
|
||||
{{ mondayBeforeToday.toLocaleDateString('de-AT') }} - {{endInterval}}
|
||||
</h4>
|
||||
<div class="d-flex align-items-center gap-2 mb-3">
|
||||
<label for="days">Anzahl Tage:</label>
|
||||
<input
|
||||
id="days"
|
||||
v-model.number="interval"
|
||||
type="number"
|
||||
class="form-control"
|
||||
style="width: 90px"
|
||||
min="1"
|
||||
max="99"
|
||||
@input="limitDays"
|
||||
>
|
||||
<label v-if="type=='oe'">{{$p.t('lehre/organisationseinheit')}}</label>
|
||||
<div v-if="type=='oe'" class="flex-grow-1">
|
||||
<form-form class="g-3" ref="oeSelectForm">
|
||||
<form-input
|
||||
container-class="w-50"
|
||||
type="autocomplete"
|
||||
name="oe_kurzbz"
|
||||
v-model="selectedOe"
|
||||
forceSelection
|
||||
optionLabel="label"
|
||||
optionValue="oe_kurzbz"
|
||||
:suggestions="filteredOes"
|
||||
dropdown
|
||||
@complete="filterOes"
|
||||
>
|
||||
<template #option="slotProps">
|
||||
<div
|
||||
:class="!slotProps.option.aktiv
|
||||
? 'item-inactive'
|
||||
: ''"
|
||||
>
|
||||
{{slotProps.option.label}}
|
||||
</div>
|
||||
</template>
|
||||
</form-input>
|
||||
</form-form>
|
||||
</div>
|
||||
<label v-if="type=='stg'">{{$p.t('zeitsperren/lektor_innen')}}</label>
|
||||
<div v-if="type=='stg'" class="flex-grow-1">
|
||||
<form-form class="g-3" ref="oeSelectForm">
|
||||
<form-input
|
||||
container-class="w-50"
|
||||
type="autocomplete"
|
||||
name="studiengang_kz"
|
||||
v-model="selectedStg"
|
||||
forceSelection
|
||||
optionLabel="label"
|
||||
optionValue="studiengang_kz"
|
||||
:suggestions="filteredStg"
|
||||
dropdown
|
||||
@complete="filterStg"
|
||||
>
|
||||
<template #option="slotProps">
|
||||
<div
|
||||
:class="!slotProps.option.aktiv
|
||||
? 'item-inactive'
|
||||
: ''"
|
||||
>
|
||||
{{slotProps.option.label}}
|
||||
</div>
|
||||
</template>
|
||||
</form-input>
|
||||
</form-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- table-->
|
||||
<div class="zeitsperrenma-content table-scroll">
|
||||
<table v-if="showTable" class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"> UID </th>
|
||||
<th v-for="day in days" :key="day.date">
|
||||
<div>{{ day.weekday }}</div>
|
||||
<div>{{ day.day }}</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="m in mitarbeiter"
|
||||
:key="m.uid"
|
||||
>
|
||||
<td>{{m.sperren[0].nachname}} {{m.sperren[0].vorname}}</td>
|
||||
<td
|
||||
v-for="day in days"
|
||||
:key="day.date"
|
||||
:class="{ 'table-warning': day.weekday === 'Sa' || day.weekday === 'So' }"
|
||||
>
|
||||
<template v-if="sperre = getSperre(m, day.date)">
|
||||
{{$p.t('zeitsperren/abwesend')}}
|
||||
<div v-if="sperre.kurzbz">
|
||||
V: <a :href="link(sperre.vertretung_uid)">
|
||||
{{ sperre.kurzbz }}
|
||||
</a>
|
||||
</div>
|
||||
<div v-if="sperre.erreichbarkeit_kurzbz">E: {{ sperre.erreichbarkeit_kurzbz }}</div>
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div v-if="!arrayMaTimelocks.length">
|
||||
<p>{{$p.t('ui/keineEintraegeGefunden')}}</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import listsZeitsperren from './Details/listsZeitsperren.js';
|
||||
import MitarbeiterZeitsperren from './Details/ZeitsperrenMitarbeiteruid.js';
|
||||
export const DEFAULT_INTERVAL_DAYS = 14;
|
||||
|
||||
export default {
|
||||
name: 'ZeitsperrenMa',
|
||||
components: {
|
||||
listsZeitsperren,
|
||||
MitarbeiterZeitsperren
|
||||
},
|
||||
props: {
|
||||
propsViewData: Object
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
activeView: null,
|
||||
buttons: [
|
||||
{
|
||||
key: 'all',
|
||||
title: 'zeitsperren/btn_all_current',
|
||||
class: 'btn-primary'
|
||||
},
|
||||
{
|
||||
key: 'fix',
|
||||
title: 'zeitsperren/btn_all_fix',
|
||||
class: 'btn-secondary'
|
||||
},
|
||||
{
|
||||
key: 'lector',
|
||||
title: 'zeitsperren/btn_fix_lect',
|
||||
class: 'btn-secondary'
|
||||
},
|
||||
{
|
||||
key: 'oe',
|
||||
title: 'zeitsperren/btn_oes',
|
||||
class: 'btn-secondary'
|
||||
},
|
||||
{
|
||||
key: 'ass',
|
||||
title: 'zeitsperren/btn_all_ass',
|
||||
class: 'btn-secondary'
|
||||
},
|
||||
{
|
||||
key: 'stg',
|
||||
title: 'zeitsperren/btn_lect_stg',
|
||||
class: 'btn-secondary'
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
show(view) {
|
||||
this.activeView = this.activeView === view ? null : view;
|
||||
},
|
||||
route(view) {
|
||||
this.activeView = this.activeView === view ? null : view;
|
||||
this.$router.push({
|
||||
name: 'ZeitsperrenMa',
|
||||
params: {
|
||||
type: this.activeView,
|
||||
days: DEFAULT_INTERVAL_DAYS
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<div class="base-zeitsperrenma">
|
||||
<div class="row g-1 flex-shrink-0">
|
||||
<div
|
||||
class="col"
|
||||
v-for="button in buttons"
|
||||
:key="button.key"
|
||||
>
|
||||
<button
|
||||
class="btn w-100"
|
||||
:class="button.class"
|
||||
@click="route(button.key)"
|
||||
>
|
||||
{{ $p.t(button.title) }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="zeitsperren-list-container">
|
||||
<lists-zeitsperren
|
||||
:type="propsViewData.type"
|
||||
:id="propsViewData.id"
|
||||
:tage="propsViewData.days"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
}
|
||||
@@ -62,6 +62,9 @@ export default {
|
||||
|
||||
return [type, result];
|
||||
}));
|
||||
},
|
||||
hiddenWidgets() {
|
||||
return this.widgets.filter(widget => widget.hidden);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -69,6 +72,9 @@ export default {
|
||||
this.$refs.widgetpicker
|
||||
.getWidget()
|
||||
.then(widget_id => {
|
||||
if (widget_id.hidden)
|
||||
this.widgetUnhide(widget_id, widget.place);
|
||||
|
||||
widget.widget = widget_id;
|
||||
// NOTE(chris): min size
|
||||
widget.place = Object.fromEntries(Object.entries(widget.place).map(([key, value]) => {
|
||||
@@ -131,17 +137,6 @@ export default {
|
||||
this.widgets.forEach((widget, i) => {
|
||||
if (failed.includes(widget.id)) {
|
||||
this.widgets[i] = structuredClone(ObjectUtils.deepToRaw(this.originalWidgets[widget.id]));
|
||||
/** NOTE(chris): if you wanna hide or unhide a
|
||||
* preset and it fails: switch around the hidden
|
||||
* value to revert it properly (checkboxes can't
|
||||
* really handle it otherwise)
|
||||
*/
|
||||
if (payload[widget.id].hidden !== undefined) {
|
||||
this.widgets[i].hidden = payload[widget.id].hidden;
|
||||
this.$nextTick(() => {
|
||||
this.widgets[i] = structuredClone(ObjectUtils.deepToRaw(this.originalWidgets[widget.id]));
|
||||
});
|
||||
}
|
||||
} else if (payload[widget.id]) {
|
||||
payload[widget.id].id = widget.id;
|
||||
payload[widget.id].index = widget.index;
|
||||
@@ -160,6 +155,31 @@ export default {
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
widgetUnhide(orig, place) {
|
||||
place = Object.fromEntries(Object.entries(place).map(([key, value]) => {
|
||||
value.w = this.sizeLimits[orig.widget].width.min;
|
||||
value.h = this.sizeLimits[orig.widget].height.min;
|
||||
// NOTE(chris): unpin pinned widgets because they got a new placement
|
||||
value.pinned = false;
|
||||
return [key, value];
|
||||
}));
|
||||
// NOTE(chris): clear placement in other screensizes
|
||||
Object.keys(orig.place).forEach(key => {
|
||||
if (!place[key]) {
|
||||
place[key] = {
|
||||
x: undefined,
|
||||
y: undefined,
|
||||
pinned: false
|
||||
};
|
||||
}
|
||||
});
|
||||
let payload = {};
|
||||
payload[orig.id] = {
|
||||
hidden: false,
|
||||
place
|
||||
};
|
||||
return this.widgetUpdate(payload);
|
||||
},
|
||||
async fetchViewData() {
|
||||
let viewDataResult = await this.$api.call(ApiDashboard.getViewData());
|
||||
const viewData = viewDataResult.data;
|
||||
@@ -204,15 +224,23 @@ export default {
|
||||
},
|
||||
template: /* html */`
|
||||
<div class="core-dashboard">
|
||||
<h3>
|
||||
{{ userFirstName ? $p.t('global/personalGreeting', [ userFirstName ]) : '' }}
|
||||
<button
|
||||
class="btn ms-2"
|
||||
aria-label="edit dashboard"
|
||||
v-tooltip="{ showDelay: 1000, value: $p.t('dashboard/edit') }"
|
||||
@click="editMode = !editMode"
|
||||
><i class="fa-solid fa-gear" aria-hidden="true"></i></button>
|
||||
</h3>
|
||||
<header class="d-flex justify-content-between align-items-baseline">
|
||||
<h3>
|
||||
{{ userFirstName ? $p.t('global/personalGreeting', [ userFirstName ]) : '' }}
|
||||
</h3>
|
||||
<div class="form-check form-check-reverse form-switch">
|
||||
<label class="form-check-label" for="switchEditMode">
|
||||
{{ $p.t('dashboard/edit') }}
|
||||
</label>
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
role="switch"
|
||||
id="switchEditMode"
|
||||
v-model="editMode"
|
||||
>
|
||||
</div>
|
||||
</header>
|
||||
<dashboard-section
|
||||
name="general"
|
||||
:widgets="widgets"
|
||||
@@ -223,6 +251,7 @@ export default {
|
||||
<dashboard-widget-picker
|
||||
ref="widgetpicker"
|
||||
:widgets="widgetsSetup"
|
||||
:hidden-widgets="hiddenWidgets"
|
||||
></dashboard-widget-picker>
|
||||
</div>`
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ export default {
|
||||
"width",
|
||||
"height",
|
||||
"custom",
|
||||
"hidden",
|
||||
"editMode",
|
||||
"loading", // widget got added and is waiting for backend to save in db
|
||||
"item_data",
|
||||
@@ -115,14 +114,6 @@ export default {
|
||||
},
|
||||
ready() {
|
||||
return this.component && this.arguments !== null;
|
||||
},
|
||||
visible: {
|
||||
get() {
|
||||
return !this.hidden;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('remove', this.hidden);
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -202,10 +193,8 @@ export default {
|
||||
},
|
||||
template: /*html*/ `
|
||||
<article
|
||||
v-if="!hidden || editMode"
|
||||
class="dashboard-item card overflow-hidden h-100 position-relative"
|
||||
:class="{
|
||||
'hidden-widget': hidden,
|
||||
[arguments?.className]: arguments && arguments.className
|
||||
}"
|
||||
>
|
||||
@@ -299,9 +288,9 @@ export default {
|
||||
>
|
||||
<i class="fa-solid fa-gear" aria-hidden="true"></i>
|
||||
</a>
|
||||
<!-- delete button -->
|
||||
<!-- delete/hide button -->
|
||||
<a
|
||||
v-if="custom && editMode"
|
||||
v-if="editMode"
|
||||
href="#"
|
||||
class="col-auto px-1"
|
||||
:aria-label="$p.t('dashboard/widget_delete')"
|
||||
@@ -310,19 +299,6 @@ export default {
|
||||
>
|
||||
<i class="fa-solid fa-trash" aria-hidden="true"></i>
|
||||
</a>
|
||||
<!-- hide button -->
|
||||
<Transition>
|
||||
<div v-if="!custom && editMode" class="col-auto px-1 form-switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
role="switch"
|
||||
v-model="visible"
|
||||
class="form-check-input ms-0"
|
||||
:value="true"
|
||||
:aria-label="$p.t('dashboard/widget_toggle_visibility')"
|
||||
>
|
||||
</div>
|
||||
</Transition>
|
||||
</header>
|
||||
<!-- TODO Manu rename/remove-->
|
||||
<div v-if="ready" class="card-body overflow-hidden p-0">
|
||||
|
||||
@@ -124,8 +124,6 @@ export default {
|
||||
return { ...item, ...placement, weight };
|
||||
});
|
||||
|
||||
if (this.editModeIsActive)
|
||||
return placedItems;
|
||||
return placedItems.filter(item => !item.hidden);
|
||||
}
|
||||
},
|
||||
@@ -141,22 +139,12 @@ export default {
|
||||
handleConfigClosed() {
|
||||
this.configOpened = false
|
||||
},
|
||||
removeWidget(item, revert) {
|
||||
removeWidget(item) {
|
||||
if (item.custom) {
|
||||
BsConfirm.popup(this.$p.t('dashboard', 'alert_deleteWidget')).then(() => this.$emit('widgetRemove', item.id, this.name));
|
||||
} else {
|
||||
let update = {};
|
||||
update[item.id] = { hidden: !revert };
|
||||
|
||||
if (!revert) {
|
||||
// NOTE(chris): move to last line
|
||||
update[item.id].place = [];
|
||||
let y = this.gridHeight;
|
||||
if (this.additionalRow)
|
||||
y--;
|
||||
update[item.id].place[this.gridWidth] = { x: 0, y };
|
||||
}
|
||||
|
||||
update[item.id] = { hidden: true };
|
||||
this.updatePreset(update);
|
||||
}
|
||||
},
|
||||
@@ -251,13 +239,12 @@ export default {
|
||||
:loading="item.loading"
|
||||
:config="item.config"
|
||||
:custom="item.custom"
|
||||
:hidden="item.hidden"
|
||||
:editMode="editModeIsActive"
|
||||
:place="item.place[gridWidth]"
|
||||
:widget-template="indexedWidgetsTemplates[item.widget]"
|
||||
:source="adminMode ? null : item.source || 'custom'"
|
||||
@change="saveConfig($event, item)"
|
||||
@remove="removeWidget(item, $event)"
|
||||
@remove="removeWidget(item)"
|
||||
@config-opened="handleConfigOpened"
|
||||
@config-closed="handleConfigClosed"
|
||||
@pin-item="updatePositions"
|
||||
|
||||
@@ -7,11 +7,21 @@ export default {
|
||||
WidgetIcon,
|
||||
},
|
||||
props: [
|
||||
"widgets"
|
||||
"widgets",
|
||||
"hiddenWidgets"
|
||||
],
|
||||
data: () => ({
|
||||
callbacks: {}
|
||||
}),
|
||||
computed: {
|
||||
hasAnyWidgets() {
|
||||
if (!this.widgets)
|
||||
return false;
|
||||
if (!this.widgets.length && !this.hiddenWidgets?.length)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getWidget() {
|
||||
return new Promise((resolve,reject) => {
|
||||
@@ -37,23 +47,46 @@ export default {
|
||||
<bs-modal
|
||||
ref="modal"
|
||||
class="fade"
|
||||
:dialog-class="{ 'modal-fullscreen-sm-down': 1, 'modal-xl': widgets && widgets.length > 0 }"
|
||||
:dialog-class="{ 'modal-fullscreen-sm-down': 1, 'modal-xl': hasAnyWidgets }"
|
||||
@hiddenBsModal="close"
|
||||
>
|
||||
<template v-slot:title>{{ $p.t('dashboard/createWidget') }}</template>
|
||||
<template v-slot:default>
|
||||
<div v-if="widgets" class="row g-2">
|
||||
<div v-if="!widgets.length">
|
||||
{{ $p.t('dashboard/noWidgetsAvailable') }}
|
||||
</div>
|
||||
<template v-if="widgets && hiddenWidgets">
|
||||
<div
|
||||
v-for="widget in widgets"
|
||||
:key="widget.widget_id"
|
||||
class="widget-icon-container col-sm-6 col-md-4 col-lg-3 col-xl-2"
|
||||
v-if="!widgets.length && !hiddenWidgets.length"
|
||||
class="row g-2"
|
||||
>
|
||||
<widget-icon @select="pick" :widget="widget"></widget-icon>
|
||||
<div>{{ $p.t('dashboard/noWidgetsAvailable') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div
|
||||
v-if="hiddenWidgets.length"
|
||||
class="row g-2"
|
||||
:class="widgets.length ? 'border-bottom pb-3 mb-3' : ''"
|
||||
>
|
||||
<div
|
||||
v-for="widget in hiddenWidgets"
|
||||
:key="widget.widget_id"
|
||||
class="widget-icon-container col-sm-6 col-md-4 col-lg-3 col-xl-2"
|
||||
>
|
||||
<widget-icon @select="pick(widget)" :widget="widgets.find(w => w.widget_id == widget.widget)"></widget-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="widgets.length"
|
||||
class="row g-2"
|
||||
>
|
||||
<div
|
||||
v-for="widget in widgets"
|
||||
:key="widget.widget_id"
|
||||
class="widget-icon-container col-sm-6 col-md-4 col-lg-3 col-xl-2"
|
||||
>
|
||||
<widget-icon @select="pick" :widget="widget"></widget-icon>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<div v-else class="text-center">
|
||||
<i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
|
||||
</div>
|
||||
|
||||
@@ -400,32 +400,37 @@ export default {
|
||||
|
||||
<div v-if="headerData.length == 1">
|
||||
<div v-if="!isLoading" class="d-flex align-items-center gap-3">
|
||||
<h2 class="h4">
|
||||
<h2 class="h4 mt-2">
|
||||
{{headerData[0].titelpre}}
|
||||
{{headerData[0].vorname}}
|
||||
{{headerData[0].nachname}}
|
||||
<span v-if="headerData[0].titelpost">, </span>
|
||||
{{headerData[0].titelpost}}
|
||||
</h2>
|
||||
<core-tag ref="tagComponent"
|
||||
v-if="tagsEnabled"
|
||||
:endpoint="tagEndpoint"
|
||||
:values="prestudentIds"
|
||||
@added="addedTag"
|
||||
@deleted="deletedTag"
|
||||
@updated="updatedTag"
|
||||
zuordnung_typ="prestudent_id"
|
||||
></core-tag>
|
||||
<div
|
||||
role="button"
|
||||
v-if="tagsEnabled"
|
||||
@click="rebuildPrestudentTags"
|
||||
class="btn btn-outline btn-light mb-1"
|
||||
:title="'Automatische Tags fuer ' + currentSemester + ' neu laden'"
|
||||
>
|
||||
<i class="fa-solid fa-refresh pe-1"></i>
|
||||
<span>{{currentSemester}}</span>
|
||||
|
||||
<div class="d-flex border rounded align-items-center ps-1">
|
||||
<core-tag ref="tagComponent"
|
||||
v-if="tagsEnabled"
|
||||
:endpoint="tagEndpoint"
|
||||
:values="prestudentIds"
|
||||
:show-hover="true"
|
||||
@added="addedTag"
|
||||
@deleted="deletedTag"
|
||||
@updated="updatedTag"
|
||||
zuordnung_typ="prestudent_id"
|
||||
></core-tag>
|
||||
<div
|
||||
role="button"
|
||||
v-if="tagsEnabled"
|
||||
@click="rebuildPrestudentTags"
|
||||
class="btn btn-outline btn-sm btn-hover m-1"
|
||||
:title="$p.t('tag','rebuild_tags') + ' ' + currentSemester"
|
||||
>
|
||||
<i class="fa-solid fa-refresh pe-1"></i>
|
||||
<span>{{currentSemester}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h6 v-if="headerData[0].unruly" class="badge" :class="'bg-unruly rounded-0'"><strong>unruly</strong></h6>
|
||||
</div>
|
||||
<div v-else class="d-flex align-items-center gap-3">
|
||||
|
||||
@@ -233,6 +233,14 @@ export default {
|
||||
if (value == oldValue)
|
||||
return;
|
||||
|
||||
/** NOTE(chris): tempPositionUpdates depends on the cols not to be
|
||||
* updated. So if they do we reset to get a clean value. In case the
|
||||
* drag and drop operation is still motion on the next tick this
|
||||
* will be correct again and if there is no such operation we clean
|
||||
* up.
|
||||
*/
|
||||
this.tempPositionUpdates = null;
|
||||
|
||||
this.reinitGrid();
|
||||
},
|
||||
rows: {
|
||||
@@ -246,6 +254,11 @@ export default {
|
||||
},
|
||||
indexedItems: {
|
||||
handler(value) {
|
||||
/** NOTE(chris): there was an update of the items, so in case
|
||||
* it came from a drag and drop operation we need to clean up
|
||||
*/
|
||||
this.tempPositionUpdates = null;
|
||||
|
||||
this.reinitGrid();
|
||||
},
|
||||
immediate: true,
|
||||
|
||||
@@ -317,6 +317,7 @@ export default {
|
||||
"$p.user_language.value"(n, o) {
|
||||
if (n !== o && o !== undefined && this.$refs.table.tableBuilt) {
|
||||
this.translateTabulator();
|
||||
this.$reloadList();
|
||||
}
|
||||
},
|
||||
"tagFilterState.selectedOptions": {
|
||||
@@ -842,35 +843,39 @@ export default {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #actions>
|
||||
<core-tag ref="tagComponent"
|
||||
v-if="tagsEnabled"
|
||||
:endpoint="tagEndpoint"
|
||||
:values="selectedColumnValues"
|
||||
@added="addedTag"
|
||||
@deleted="deletedTag"
|
||||
@updated="updatedTag"
|
||||
zuordnung_typ="prestudent_id"
|
||||
></core-tag>
|
||||
<template #tags>
|
||||
<div class="d-flex border rounded align-items-center ps-1">
|
||||
<core-tag ref="tagComponent"
|
||||
v-if="tagsEnabled"
|
||||
:endpoint="tagEndpoint"
|
||||
:values="selectedColumnValues"
|
||||
@added="addedTag"
|
||||
@deleted="deletedTag"
|
||||
@updated="updatedTag"
|
||||
zuordnung_typ="prestudent_id"
|
||||
show-hover
|
||||
></core-tag>
|
||||
|
||||
<button
|
||||
v-if="!selected.length"
|
||||
class="btn btn-outline btn-light mb-1"
|
||||
@click="rebuild(selected)"
|
||||
:title="$p.t('tag','rebuild_tags') + ' Stg ' + currentSemester"
|
||||
>
|
||||
<i class="fa-solid fa-refresh pe-1"></i> STG
|
||||
</button>
|
||||
<button
|
||||
v-else
|
||||
class="btn btn-outline btn-light mb-1"
|
||||
@click="rebuild(selected)"
|
||||
:title="$p.t('tag','rebuild_tags') + ' ' + $p.t('ui','selection') + ' ' + currentSemester"
|
||||
>
|
||||
<i class="fa-solid fa-refresh pe-1"></i> {{selected.length}}
|
||||
</button>
|
||||
<button
|
||||
v-if="!selected.length"
|
||||
class="btn btn-outline btn-sm m-1 btn-hover"
|
||||
@click="rebuild(selected)"
|
||||
:title="$p.t('tag','rebuild_tags') + ' Stg ' + currentSemester"
|
||||
>
|
||||
<i class="fa-solid fa-refresh pe-1"></i> STG
|
||||
</button>
|
||||
<button
|
||||
v-else
|
||||
class="btn btn-outline btn-sm m-1 btn-hover"
|
||||
@click="rebuild(selected)"
|
||||
:title="$p.t('tag','rebuild_tags') + ' ' + $p.t('ui','selection') + ' ' + currentSemester"
|
||||
>
|
||||
<i class="fa-solid fa-refresh pe-1"></i> {{selected.length}}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="filter.length || headerFilterActive">
|
||||
<template v-if="filter.length || headerFilterActive">
|
||||
<div class="d-flex justify-content-center align-items-center gap-2 ps-4 position-absolute start-50 translate-middle-x">
|
||||
<p class="text-danger mb-0">
|
||||
<strong>{{$p.t('filter','filterActive')}}</strong>
|
||||
@@ -884,8 +889,6 @@ export default {
|
||||
<span class="fa-solid fa-filter-circle-xmark"></span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</template>
|
||||
|
||||
<template #filter>
|
||||
@@ -895,6 +898,7 @@ export default {
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</core-filter-cmpt>
|
||||
</div>
|
||||
<list-new ref="new" :studiengang-kz="studiengangKz" :studiensemester-kurzbz="studiensemesterKurzbz"></list-new>
|
||||
|
||||
@@ -28,6 +28,10 @@ export default {
|
||||
confirmLimit: {
|
||||
type: Number,
|
||||
default: 20
|
||||
},
|
||||
showHover: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -228,7 +232,8 @@ export default {
|
||||
<span :title="values.length === 0 ? 'Bitte Zeilen markieren' : ''">
|
||||
<button @mouseover="showList = true"
|
||||
:disabled="!values || values.length === 0"
|
||||
class="btn btn-sm">
|
||||
class="btn btn-sm"
|
||||
:class="{'btn-hover': showHover}">
|
||||
<i class="fa-solid fa-tag fa-xl"></i>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
@@ -5,7 +5,6 @@ import VertraegeMitarbeiter from "./Vertraege.js";
|
||||
import VerticalSplit from "../verticalsplit/verticalsplit.js";
|
||||
import ApiCoreVertraege from '../../api/factory/vertraege/vertraege.js';
|
||||
|
||||
|
||||
export default {
|
||||
name: 'Vertragsverwaltung',
|
||||
components: {
|
||||
|
||||
@@ -1094,7 +1094,7 @@ export const CoreFilterCmpt = {
|
||||
<div :id="'filterCollapsables' + idExtra">
|
||||
|
||||
<div class="d-flex flex-row justify-content-between flex-wrap">
|
||||
<div v-if="newBtnShow || reload || $slots.search || $slots.actions" class="d-flex gap-2 align-items-baseline flex-wrap">
|
||||
<div v-if="newBtnShow || reload || $slots.search || $slots.actions || $slots.tags" class="d-flex gap-2 align-items-baseline flex-wrap">
|
||||
<button v-if="newBtnShow" class="btn btn-primary" :class="newBtnClass" :title="newBtnLabel ? undefined : 'New'" :aria-label="newBtnLabel ? undefined : 'New'" @click="$emit('click:new', $event)" :disabled="newBtnDisabled">
|
||||
<span class="fa-solid fa-plus" aria-hidden="true"></span>
|
||||
{{ newBtnLabel }}
|
||||
@@ -1107,6 +1107,7 @@ export const CoreFilterCmpt = {
|
||||
<span v-else id="selected-info-text"> Mit {{ selectedData.length }} ausgewählten:</span>
|
||||
</span>
|
||||
<slot name="actions" v-bind="{selected: tabulatorHasSelector ? selectedData : []}"></slot>
|
||||
<slot name="tags"></slot>
|
||||
<slot name="search"></slot>
|
||||
</div>
|
||||
<div class="d-flex gap-1 align-items-baseline flex-grow-1 justify-content-end">
|
||||
|
||||
@@ -40,7 +40,7 @@ export default {
|
||||
query: Vue.computed(() => this.lastQuery),
|
||||
};
|
||||
},
|
||||
inject: ["isMobile"],
|
||||
inject: { isMobile: { default: false } },
|
||||
data: function () {
|
||||
return {
|
||||
searchtimer: null,
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../vendor
|
||||
@@ -100,6 +100,7 @@ require_once('dbupdate_3.4/68530_Dashboard_Cleanup.php');
|
||||
require_once('dbupdate_3.4/75959_StudVw_Automatische_Tags.php');
|
||||
require_once('dbupdate_3.4/76160_lvv_favorites.php');
|
||||
require_once('dbupdate_3.4/77080_tabulator_presets_table.php');
|
||||
require_once('dbupdate_3.4/78292_gehaltsanpassungtyp.php');
|
||||
|
||||
// *** Pruefung und hinzufuegen der neuen Attribute und Tabellen
|
||||
echo '<H2>Pruefe Tabellen und Attribute!</H2>';
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
if (! defined('DB_NAME')) exit('No direct script access allowed');
|
||||
|
||||
if ($result = $db->db_query("SELECT * FROM information_schema.tables WHERE table_name='tbl_gehaltsanpassungtyp' AND table_schema='hr'"))
|
||||
{
|
||||
if ($db->db_num_rows($result) == 0)
|
||||
{
|
||||
$qry = "
|
||||
|
||||
ALTER TABLE
|
||||
hr.tbl_gehaltsbestandteil
|
||||
ADD COLUMN IF NOT EXISTS
|
||||
gehaltsanpassungtyp_kurzbz character varying(32);
|
||||
|
||||
COMMENT ON COLUMN hr.tbl_gehaltsbestandteil.gehaltsanpassungtyp_kurzbz IS E'Ersteinstufung, indiv. Erhöhung, etc.';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS hr.tbl_gehaltsanpassungtyp
|
||||
(
|
||||
gehaltsanpassungtyp_kurzbz character varying(32) NOT NULL,
|
||||
bezeichnung varchar(256),
|
||||
sort smallint,
|
||||
aktiv boolean NOT NULL DEFAULT true,
|
||||
CONSTRAINT tbl_gehaltsanpassungtyp_pk PRIMARY KEY (gehaltsanpassungtyp_kurzbz)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE hr.tbl_gehaltsanpassungtyp IS E'Key-Table of Salary Adaption Types';
|
||||
|
||||
ALTER TABLE hr.tbl_gehaltsbestandteil DROP CONSTRAINT IF EXISTS tbl_gehaltsanpassungtyp_fk;
|
||||
ALTER TABLE hr.tbl_gehaltsbestandteil ADD CONSTRAINT tbl_gehaltsanpassungtyp_fk FOREIGN KEY (gehaltsanpassungtyp_kurzbz)
|
||||
REFERENCES hr.tbl_gehaltsanpassungtyp (gehaltsanpassungtyp_kurzbz) MATCH FULL
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
GRANT SELECT, UPDATE, INSERT, DELETE ON hr.tbl_gehaltsanpassungtyp TO vilesci;
|
||||
|
||||
INSERT INTO hr.tbl_gehaltsanpassungtyp(gehaltsanpassungtyp_kurzbz, bezeichnung, sort, aktiv) VALUES('ersteinstufung','Ersteinstufung', 1, true);
|
||||
INSERT INTO hr.tbl_gehaltsanpassungtyp(gehaltsanpassungtyp_kurzbz, bezeichnung, sort, aktiv) VALUES('individuelle_erhoehung','Indiv. Gehaltserhöhung', 2, true);
|
||||
INSERT INTO hr.tbl_gehaltsanpassungtyp(gehaltsanpassungtyp_kurzbz, bezeichnung, sort, aktiv) VALUES('strukturelle_anpassung','Strukturelle Anpassung', 3, true);
|
||||
INSERT INTO hr.tbl_gehaltsanpassungtyp(gehaltsanpassungtyp_kurzbz, bezeichnung, sort, aktiv) VALUES('funktionsaenderung','Funktionsänderung', 4, true);
|
||||
|
||||
";
|
||||
|
||||
if (! $db->db_query($qry))
|
||||
echo '<strong>Gehaltsanpassungtyp: ' . $db->db_last_error() . '</strong><br>';
|
||||
else
|
||||
echo 'Tabelle und Feld für Gehaltsanpassungtyp wurden neu erstellt<br>';
|
||||
}
|
||||
}
|
||||
+1072
-400
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user