mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-06-12 09:39:28 +00:00
new Core Component Function
- autocomplete and dropdown field for search oes and search functions with active and non active entries - possibility to dynamic styling of display switch, newButton in Tabulator, different editLabels - possibility to show/hide column company - possibility to show/hide to save function as copy
This commit is contained in:
@@ -0,0 +1,385 @@
|
||||
<?php
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
use \DateTime as DateTime;
|
||||
|
||||
class Funktionen extends FHCAPI_Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
//TODO(Manu) check permissions
|
||||
parent::__construct(array(
|
||||
'getAllFunctions' => ['admin:r', 'assistenz:r'],
|
||||
'getContractFunctions' => ['admin:r', 'assistenz:r'],
|
||||
'getCurrentFunctions' => ['admin:r', 'assistenz:r'],
|
||||
'getAllUserFunctions' => ['admin:r', 'assistenz:r'],
|
||||
'getOrgHeads' => ['admin:r', 'assistenz:r'],
|
||||
'getOrgetsForCompany' => ['admin:r', 'assistenz:r'],
|
||||
'loadAllOes' => ['admin:r', 'assistenz:r'],
|
||||
'searchOes' => ['admin:r', 'assistenz:r'],
|
||||
'searchFunctions' => ['admin:r', 'assistenz:r'],
|
||||
'loadFunction' => ['admin:r', 'assistenz:r'],
|
||||
'insertFunction' => ['admin:rw', 'assistenz:rw'],
|
||||
'updateFunction' => ['admin:rw', 'assistenz:rw'],
|
||||
'deleteFunction' => ['admin:rw', 'assistenz:rw'],
|
||||
)
|
||||
);
|
||||
|
||||
// Load Libraries
|
||||
$this->load->library('VariableLib', ['uid' => getAuthUID()]);
|
||||
$this->load->library('form_validation');
|
||||
|
||||
// Load language phrases
|
||||
$this->loadPhrases([
|
||||
'ui',
|
||||
]);
|
||||
|
||||
// Load models
|
||||
$this->load->model('extensions/FHC-Core-Personalverwaltung/Api_model', 'ApiModel');
|
||||
$this->load->model('ressource/Funktion_model', 'FunktionModel');
|
||||
$this->load->model('person/Benutzerfunktion_model', 'BenutzerfunktionModel');
|
||||
|
||||
$this->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel');
|
||||
}
|
||||
|
||||
public function getOrgHeads()
|
||||
{
|
||||
$result = $this->OrganisationseinheitModel->getHeads();
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function getAllUserFunctions($uid)
|
||||
{
|
||||
if(!$uid)
|
||||
{
|
||||
$this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'UID']), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
|
||||
$sql = "
|
||||
SELECT
|
||||
dv.dienstverhaeltnis_id,
|
||||
un.bezeichnung || ' (' || TO_CHAR(dv.von, 'DD.MM.YYYY') || CASE WHEN dv.bis IS NOT NULL THEN ' - '
|
||||
|| TO_CHAR(dv.bis, 'DD.MM.YYYY') ELSE '' END || ')' AS dienstverhaeltnis_unternehmen ,
|
||||
'[' || oet.bezeichnung || '] ' || oe.bezeichnung AS funktion_oebezeichnung,
|
||||
f.beschreibung AS funktion_beschreibung,
|
||||
bf.*,
|
||||
fb.bezeichnung AS fachbereich_bezeichnung,
|
||||
CASE
|
||||
WHEN
|
||||
bf.datum_bis IS NOT NULL AND bf.datum_bis::date < now()::date
|
||||
THEN
|
||||
false
|
||||
ELSE
|
||||
true
|
||||
END aktiv
|
||||
FROM
|
||||
public.tbl_benutzerfunktion bf
|
||||
JOIN
|
||||
public.tbl_organisationseinheit oe ON oe.oe_kurzbz = bf.oe_kurzbz
|
||||
JOIN
|
||||
public.tbl_organisationseinheittyp oet ON oe.organisationseinheittyp_kurzbz = oet.organisationseinheittyp_kurzbz
|
||||
JOIN
|
||||
public.tbl_funktion f ON f.funktion_kurzbz = bf.funktion_kurzbz
|
||||
LEFT JOIN
|
||||
hr.tbl_vertragsbestandteil_funktion vf ON vf.benutzerfunktion_id = bf.benutzerfunktion_id
|
||||
LEFT JOIN
|
||||
hr.tbl_vertragsbestandteil v ON vf.vertragsbestandteil_id = v.vertragsbestandteil_id
|
||||
LEFT JOIN
|
||||
hr.tbl_dienstverhaeltnis dv ON v.dienstverhaeltnis_id = dv.dienstverhaeltnis_id
|
||||
LEFT JOIN
|
||||
public.tbl_organisationseinheit un ON dv.oe_kurzbz = un.oe_kurzbz
|
||||
LEFT JOIN
|
||||
public.tbl_fachbereich fb ON fb.fachbereich_kurzbz = bf.fachbereich_kurzbz
|
||||
WHERE
|
||||
bf.uid = ?
|
||||
ORDER BY
|
||||
f.beschreibung, bf.datum_von ASC";
|
||||
|
||||
$benutzerfunktionen = $this->BenutzerfunktionModel->execReadOnlyQuery($sql, array($uid));
|
||||
$data = $this->getDataOrTerminateWithError($benutzerfunktionen);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
//TODO(Manu) DELETE
|
||||
public function DEPR_getCurrentFunctions($uid, $companyOrgetkurzbz)
|
||||
{
|
||||
$sql = "
|
||||
SELECT
|
||||
bf.benutzerfunktion_id, f.beschreibung || ', '
|
||||
|| oe.bezeichnung || ' [' || oet.bezeichnung || '], '
|
||||
|| COALESCE(to_char(bf.datum_von, 'dd.mm.YYYY'), 'n/a')
|
||||
|| ' - ' || COALESCE(to_char(bf.datum_bis, 'dd.mm.YYYY'), 'n/a')
|
||||
|| COALESCE(dvu.attachedtovb, '') AS label
|
||||
|
||||
FROM (
|
||||
WITH RECURSIVE oes(oe_kurzbz, oe_parent_kurzbz) as
|
||||
(
|
||||
SELECT oe_kurzbz, oe_parent_kurzbz FROM public.tbl_organisationseinheit
|
||||
WHERE oe_kurzbz = ?
|
||||
UNION ALL
|
||||
SELECT o.oe_kurzbz, o.oe_parent_kurzbz FROM public.tbl_organisationseinheit o, oes
|
||||
WHERE o.oe_parent_kurzbz=oes.oe_kurzbz
|
||||
)
|
||||
SELECT oe_kurzbz
|
||||
FROM oes
|
||||
GROUP BY oe_kurzbz
|
||||
) c
|
||||
JOIN public.tbl_organisationseinheit oe ON oe.oe_kurzbz = c.oe_kurzbz
|
||||
JOIN public.tbl_organisationseinheittyp oet ON oe.organisationseinheittyp_kurzbz = oet.organisationseinheittyp_kurzbz
|
||||
JOIN public.tbl_benutzerfunktion bf ON bf.oe_kurzbz = oe.oe_kurzbz
|
||||
JOIN public.tbl_funktion f ON f.funktion_kurzbz = bf.funktion_kurzbz
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
benutzerfunktion_id, ' [DV]' AS attachedtovb
|
||||
FROM
|
||||
hr.tbl_vertragsbestandteil_funktion
|
||||
GROUP BY
|
||||
benutzerfunktion_id
|
||||
) dvu ON dvu.benutzerfunktion_id = bf.benutzerfunktion_id
|
||||
WHERE bf.uid = ?
|
||||
ORDER BY f.beschreibung ASC";
|
||||
|
||||
$benutzerfunktionen = $this->BenutzerfunktionModel->execReadOnlyQuery($sql, array( $companyOrgetkurzbz,$uid));
|
||||
$data = $this->getDataOrTerminateWithError($benutzerfunktionen);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
/*
|
||||
* return list of child orgets for a given company orget_kurzbz
|
||||
* as key value list to be used in select or autocomplete
|
||||
*/
|
||||
public function getOrgetsForCompany($companyOrgetkurzbz=null)
|
||||
{
|
||||
$sql = "
|
||||
SELECT
|
||||
oe.oe_kurzbz,
|
||||
'[' || COALESCE(oet.bezeichnung, oet.organisationseinheittyp_kurzbz) ||
|
||||
'] ' || COALESCE(oe.bezeichnung, oe.oe_kurzbz) AS label
|
||||
FROM (
|
||||
WITH RECURSIVE oes(oe_kurzbz, oe_parent_kurzbz) as
|
||||
(
|
||||
SELECT oe_kurzbz, oe_parent_kurzbz FROM public.tbl_organisationseinheit
|
||||
WHERE oe_kurzbz=?
|
||||
UNION ALL
|
||||
SELECT o.oe_kurzbz, o.oe_parent_kurzbz FROM public.tbl_organisationseinheit o, oes
|
||||
WHERE o.oe_parent_kurzbz=oes.oe_kurzbz
|
||||
)
|
||||
SELECT oe_kurzbz
|
||||
FROM oes
|
||||
GROUP BY oe_kurzbz
|
||||
) c
|
||||
JOIN public.tbl_organisationseinheit oe ON oe.oe_kurzbz = c.oe_kurzbz
|
||||
JOIN public.tbl_organisationseinheittyp oet ON oe.organisationseinheittyp_kurzbz = oet.organisationseinheittyp_kurzbz
|
||||
ORDER BY oet.bezeichnung ASC, oe.bezeichnung ASC";
|
||||
|
||||
$childorgets = $this->OrganisationseinheitModel->execReadOnlyQuery($sql, array($companyOrgetkurzbz));
|
||||
$data = $this->getDataOrTerminateWithError($childorgets);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
//TODO(Manu) DELETE
|
||||
/*
|
||||
* List of Oes for autocomplete field organisation unit
|
||||
*/
|
||||
public function DEPR_loadAllOes($filterStudent=false, $aktiv=true)
|
||||
{
|
||||
$sql = "
|
||||
SELECT
|
||||
oe_kurzbz,
|
||||
CONCAT('[', organisationseinheittyp_kurzbz, '] ', bezeichnung) as label
|
||||
FROM public.tbl_organisationseinheit
|
||||
WHERE aktiv = ?";
|
||||
|
||||
if($filterStudent)
|
||||
$sql .= " AND organisationseinheittyp_kurzbz in ('Studiengang','Lehrgang')";
|
||||
|
||||
$sql .= " ORDER BY organisationseinheittyp_kurzbz, bezeichnung";
|
||||
|
||||
$result = $this->OrganisationseinheitModel->execReadOnlyQuery($sql, array($aktiv));
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function searchOes($companyOrgetKurzbz, $searchString = null)
|
||||
{
|
||||
$result = $this->OrganisationseinheitModel->getAutocompleteSuggestionsWithCompany($companyOrgetKurzbz, $searchString);
|
||||
if (isError($result)) {
|
||||
$this->terminateWithError($result, self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
$this->terminateWithSuccess($result ?: []);
|
||||
}
|
||||
|
||||
public function searchFunctions($searchString = null)
|
||||
{
|
||||
|
||||
$result = $this->FunktionModel->getAutocompleteSuggestions($searchString);
|
||||
if (isError($result)) {
|
||||
$this->terminateWithError($result, self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
$this->terminateWithSuccess($result ?: []);
|
||||
}
|
||||
|
||||
public function loadFunction($benutzerfunktion_id)
|
||||
{
|
||||
$this->BenutzerfunktionModel->addSelect("*");
|
||||
$result = $this->BenutzerfunktionModel->loadWhere(
|
||||
array('benutzerfunktion_id' => $benutzerfunktion_id)
|
||||
);
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess(current($data));
|
||||
}
|
||||
|
||||
public function insertFunction()
|
||||
{
|
||||
$this->load->library('form_validation');
|
||||
$authUID = getAuthUID();
|
||||
|
||||
$uid = $this->input->post('uid');
|
||||
|
||||
if(!$uid)
|
||||
{
|
||||
return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'UID']), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
|
||||
$formData = $this->input->post('formData');
|
||||
|
||||
$datum_von = $formData['datum_von'] ?? null;
|
||||
$datum_bis = $formData['datum_bis'] ?? null;
|
||||
$formData['oe_kurzbz'] = is_array($formData['oe_kurzbz']) ? $formData['oe_kurzbz']['oe_kurzbz'] : $formData['oe_kurzbz'];
|
||||
$formData['funktion_kurzbz'] = is_array($formData['funktion_kurzbz'])
|
||||
? $formData['funktion_kurzbz']['funktion_kurzbz']
|
||||
: $formData['funktion_kurzbz'];
|
||||
$bezeichnung = $formData['bezeichnung'] ?? null;
|
||||
$wochenstunden = $formData['wochenstunden'] ?? null;
|
||||
|
||||
$this->form_validation->set_data($formData);
|
||||
$this->form_validation->set_rules('datum_von', '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('datum_bis', 'BisDatum', 'is_valid_date', [
|
||||
'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'BisDatum'])
|
||||
]);
|
||||
$this->form_validation->set_rules('oe_kurzbz', 'Organisationseinheit', 'required', [
|
||||
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Organisationseinheit'])
|
||||
]);
|
||||
$this->form_validation->set_rules('funktion_kurzbz', 'Funktion', 'required', [
|
||||
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Funktion'])
|
||||
]);
|
||||
$this->form_validation->set_rules('wochenstunden', 'Wochenstunden', 'numeric', [
|
||||
'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Wochenstunden'])
|
||||
]);
|
||||
|
||||
if ($this->form_validation->run() == false)
|
||||
{
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
}
|
||||
|
||||
$result = $this->BenutzerfunktionModel->insert([
|
||||
'uid' => $uid,
|
||||
'datum_von' => $datum_von,
|
||||
'datum_bis' => $datum_bis ,
|
||||
'oe_kurzbz' => $formData['oe_kurzbz'],
|
||||
'funktion_kurzbz' => $formData['funktion_kurzbz'],
|
||||
'bezeichnung' => $bezeichnung,
|
||||
'wochenstunden' => $wochenstunden,
|
||||
'insertamum' => date('c'),
|
||||
'insertvon' => $authUID,
|
||||
]);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function updateFunction()
|
||||
{
|
||||
$this->load->library('form_validation');
|
||||
$authUID = getAuthUID();
|
||||
|
||||
$uid = $this->input->post('uid');
|
||||
|
||||
if(!$uid)
|
||||
{
|
||||
return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'UID']), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
$benutzerfunktion_id = $this->input->post('benutzerfunktion_id');
|
||||
|
||||
if(!$benutzerfunktion_id)
|
||||
{
|
||||
return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Benutzerfunktion ID']), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
|
||||
$formData = $this->input->post('formData');
|
||||
|
||||
$datum_von = $formData['datum_von'] ?? null;
|
||||
$datum_bis = $formData['datum_bis'] ?? null;
|
||||
$formData['oe_kurzbz'] = is_array($formData['oe_kurzbz']) ? $formData['oe_kurzbz']['oe_kurzbz'] : $formData['oe_kurzbz'];
|
||||
$formData['funktion_kurzbz'] = is_array($formData['funktion_kurzbz'])
|
||||
? $formData['funktion_kurzbz']['funktion_kurzbz']
|
||||
: $formData['funktion_kurzbz'];
|
||||
$bezeichnung = $formData['bezeichnung'] ?? null;
|
||||
$wochenstunden = $formData['wochenstunden'] ?? null;
|
||||
|
||||
$this->form_validation->set_data($formData);
|
||||
$this->form_validation->set_rules('datum_von', '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('datum_bis', 'BisDatum', 'is_valid_date', [
|
||||
'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'BisDatum'])
|
||||
]);
|
||||
$this->form_validation->set_rules('oe_kurzbz', 'Organisationseinheit', 'required', [
|
||||
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Organisationseinheit'])
|
||||
]);
|
||||
$this->form_validation->set_rules('funktion_kurzbz', 'Funktion', 'required', [
|
||||
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Funktion'])
|
||||
]);
|
||||
$this->form_validation->set_rules('wochenstunden', 'Wochenstunden', 'numeric', [
|
||||
'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Wochenstunden'])
|
||||
]);
|
||||
|
||||
if ($this->form_validation->run() == false)
|
||||
{
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
}
|
||||
|
||||
$result = $this->BenutzerfunktionModel->update(
|
||||
[
|
||||
'benutzerfunktion_id' => $benutzerfunktion_id,
|
||||
],
|
||||
[
|
||||
'uid' => $uid,
|
||||
'datum_von' => $datum_von,
|
||||
'datum_bis' => $datum_bis ,
|
||||
'oe_kurzbz' => $formData['oe_kurzbz'],
|
||||
'funktion_kurzbz' => $formData['funktion_kurzbz'],
|
||||
'bezeichnung' => $bezeichnung,
|
||||
'wochenstunden' => $wochenstunden,
|
||||
'updateamum' => date('c'),
|
||||
'updatevon' => $authUID,
|
||||
]
|
||||
);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function deleteFunction($benutzerfunktion_id)
|
||||
{
|
||||
$result = $this->BenutzerfunktionModel->delete(
|
||||
array('benutzerfunktion_id' => $benutzerfunktion_id)
|
||||
);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
}
|
||||
@@ -132,6 +132,11 @@ class Config extends FHCAPI_Controller
|
||||
'title' => $this->p->t('stv', 'tab_functions'),
|
||||
'component' => './Stv/Studentenverwaltung/Details/Funktionen.js'
|
||||
];
|
||||
/* TODO(Manu) REMOVE just for Testing*/
|
||||
$result['functions_composition'] = [
|
||||
'title' => 'F_PV21',
|
||||
'component' => './Stv/Studentenverwaltung/Details/FunktionenOld.js'
|
||||
];
|
||||
|
||||
Events::trigger('stv_conf_student', function & () use (&$result) {
|
||||
return $result;
|
||||
|
||||
@@ -217,4 +217,72 @@ class Organisationseinheit_model extends DB_Model
|
||||
oe_kurzbz ILIKE '%". $this->escapeLike($eventQuery). "%'
|
||||
");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OEs by eventQuery string and companyOrgetKurzbz
|
||||
* Use with autocomplete event queries in Function Component
|
||||
* @param $searchString String
|
||||
* @param $companyOrgetKurzbz String oe_kurzbz of the company (gst vs gmbh)
|
||||
* @return array
|
||||
*/
|
||||
public function getAutocompleteSuggestionsWithCompany($companyOrgetKurzbz, $searchString)
|
||||
{
|
||||
$sql = "
|
||||
WITH RECURSIVE oes(oe_kurzbz, oe_parent_kurzbz) AS (
|
||||
SELECT oe_kurzbz, oe_parent_kurzbz
|
||||
FROM public.tbl_organisationseinheit
|
||||
WHERE oe_kurzbz = ?
|
||||
UNION ALL
|
||||
SELECT o.oe_kurzbz, o.oe_parent_kurzbz
|
||||
FROM public.tbl_organisationseinheit o
|
||||
INNER JOIN oes ON o.oe_parent_kurzbz = oes.oe_kurzbz
|
||||
)
|
||||
SELECT
|
||||
oe.oe_kurzbz, oe.aktiv,
|
||||
'[' || COALESCE(oet.bezeichnung, oet.organisationseinheittyp_kurzbz) ||
|
||||
'] ' || COALESCE(oe.bezeichnung, oe.oe_kurzbz) AS label
|
||||
FROM (
|
||||
SELECT oe_kurzbz FROM oes GROUP BY oe_kurzbz
|
||||
) c
|
||||
JOIN public.tbl_organisationseinheit oe ON oe.oe_kurzbz = c.oe_kurzbz
|
||||
JOIN public.tbl_organisationseinheittyp oet ON oe.organisationseinheittyp_kurzbz = oet.organisationseinheittyp_kurzbz
|
||||
";
|
||||
|
||||
$params = [$companyOrgetKurzbz];
|
||||
|
||||
if (!empty($searchString)) {
|
||||
$escaped = $this->escapeLike($searchString);
|
||||
$ilike = '%' . $escaped . '%';
|
||||
|
||||
$sql .= "
|
||||
WHERE
|
||||
oe.oe_kurzbz ILIKE ? OR
|
||||
oe.bezeichnung ILIKE ? OR
|
||||
oe.organisationseinheittyp_kurzbz ILIKE ?
|
||||
";
|
||||
|
||||
$params[] = $ilike;
|
||||
$params[] = $ilike;
|
||||
$params[] = $ilike;
|
||||
}
|
||||
|
||||
$sql .= " ORDER BY oet.bezeichnung ASC, oe.bezeichnung ASC";
|
||||
|
||||
$result = $this->execQuery($sql, $params);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get highest organisation units
|
||||
*/
|
||||
public function getHeads()
|
||||
{
|
||||
$this->addSelect('*');
|
||||
$this->addSelect('oe_kurzbz as head');
|
||||
$result = $this->loadWhere(array('oe_parent_kurzbz' => null, 'aktiv' => true));
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,4 +11,26 @@ class Funktion_model extends DB_Model
|
||||
$this->dbTable = 'public.tbl_funktion';
|
||||
$this->pk = 'funktion_kurzbz';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Functions by eventQuery string. Use with autocomplete event queries in Function Component
|
||||
* @param $eventQuery String
|
||||
* @return array
|
||||
*/
|
||||
public function getAutocompleteSuggestions($eventQuery)
|
||||
{
|
||||
$this->addSelect('funktion_kurzbz, beschreibung, aktiv');
|
||||
$this->addSelect("beschreibung AS label");
|
||||
$this->addOrder('beschreibung', 'ASC');
|
||||
|
||||
if($eventQuery === null)
|
||||
{
|
||||
return $this->load();
|
||||
}
|
||||
|
||||
return $this->loadWhere("
|
||||
funktion_kurzbz ILIKE '%". $this->escapeLike($eventQuery). "%'
|
||||
OR beschreibung ILIKE '%". $this->escapeLike($eventQuery). "%'
|
||||
");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
#datepicker fuer component functions
|
||||
'public/css/components/vue-datepicker.css',
|
||||
'public/css/components/primevue.css',
|
||||
'public/css/Studentenverwaltung.css'
|
||||
'public/css/Studentenverwaltung.css',
|
||||
'public/css/components/function.css'
|
||||
],
|
||||
'customJSs' => [
|
||||
'vendor/vuejs/vuedatepicker_js/vue-datepicker.iife.js'
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.item-inactive {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright (C) 2025 fhcomplete.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
export default {
|
||||
getContractFunctions(filter) {
|
||||
var url = 'api/frontend/v1/funktionen/Funktionen/getContractFunctions';
|
||||
if( typeof filter !== 'undefined' && filter !== null ) {
|
||||
url = url + '/' + filter;
|
||||
}
|
||||
return {
|
||||
method: 'get',
|
||||
url,
|
||||
};
|
||||
|
||||
},
|
||||
getOrgHeads() {
|
||||
var url = 'api/frontend/v1/funktionen/Funktionen/getOrgHeads';
|
||||
return {
|
||||
method: 'get',
|
||||
url,
|
||||
};
|
||||
},
|
||||
getOrgetsForCompany(unternehmen) {
|
||||
var url = 'api/frontend/v1/funktionen/Funktionen/getOrgetsForCompany'
|
||||
+ '/' + unternehmen;
|
||||
return {
|
||||
method: 'get',
|
||||
url,
|
||||
};
|
||||
},
|
||||
loadAllOes(filterStudent) {
|
||||
var url = 'api/frontend/v1/funktionen/Funktionen/loadAllOes'
|
||||
+ '/' + filterStudent;
|
||||
return {
|
||||
method: 'get',
|
||||
url,
|
||||
};
|
||||
},
|
||||
getCompanyByOrget(orget) {
|
||||
var url = 'api/frontend/v1/funktionen/Funktionen/getCompanyByOrget'
|
||||
+ '/' + orget;
|
||||
return {
|
||||
method: 'get',
|
||||
url,
|
||||
};
|
||||
},
|
||||
getCurrentFunctions(mitarbeiter_uid, unternehmen) {
|
||||
var url = 'api/frontend/v1/funktionen/Funktionen/getCurrentFunctions'
|
||||
+ '/' + mitarbeiter_uid + '/' + unternehmen;
|
||||
return {
|
||||
method: 'get',
|
||||
url,
|
||||
};
|
||||
} ,
|
||||
getAllUserFunctions(mitarbeiter_uid) {
|
||||
var url = 'api/frontend/v1/funktionen/Funktionen/getAllUserFunctions'
|
||||
+ '/' + mitarbeiter_uid;
|
||||
return {
|
||||
method: 'get',
|
||||
url,
|
||||
};
|
||||
},
|
||||
getAllFunctions() {
|
||||
var url = 'api/frontend/v1/funktionen/Funktionen/getAllFunctions';
|
||||
return {
|
||||
method: 'get',
|
||||
url,
|
||||
};
|
||||
},
|
||||
addFunction(params) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: 'api/frontend/v1/funktionen/Funktionen/insertFunction/',
|
||||
params
|
||||
};
|
||||
},
|
||||
loadFunction(benutzerfunktion_id) {
|
||||
var url = 'api/frontend/v1/funktionen/Funktionen/loadFunction'
|
||||
+ '/' + benutzerfunktion_id;
|
||||
return {
|
||||
method: 'get',
|
||||
url,
|
||||
};
|
||||
},
|
||||
updateFunction(params) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: 'api/frontend/v1/funktionen/Funktionen/updateFunction/',
|
||||
params
|
||||
};
|
||||
},
|
||||
deleteFunction(benutzerfunktion_id) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: 'api/frontend/v1/funktionen/Funktionen/deleteFunction/' + benutzerfunktion_id
|
||||
};
|
||||
},
|
||||
getOes(head, searchString) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: 'api/frontend/v1/funktionen/Funktionen/searchOes/' + head + '/' + searchString
|
||||
};
|
||||
},
|
||||
getFunctions(searchString) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: 'api/frontend/v1/funktionen/Funktionen/searchFunctions/' + searchString
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,622 @@
|
||||
import { Modal } from './Modal.js';
|
||||
import { ModalDialog } from './ModalDialog.js';
|
||||
import { Toast } from './Toast.js';
|
||||
import {OrgChooser} from "./OrgChooser.js";
|
||||
import { usePhrasen } from '../../mixins/Phrasen.js';
|
||||
|
||||
import ApiFunktion from '../../api/factory/funktionen/person.js';
|
||||
import ApiPerson from "../../../extensions/FHC-Core-Personalverwaltung/js/api/factory/person.js";
|
||||
|
||||
export const Funktionen = {
|
||||
name: 'FunctionComponentOld',
|
||||
components: {
|
||||
Modal,
|
||||
ModalDialog,
|
||||
Toast,
|
||||
OrgChooser,
|
||||
"datepicker": VueDatePicker
|
||||
},
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => ({}), required: false},
|
||||
config: { type: Object, default: () => ({}), required: false},
|
||||
readonlyMode: { type: Boolean, required: false, default: false },
|
||||
personID: { type: Number, required: false },
|
||||
personUID: { type: String, required: false },
|
||||
writePermission: { type: Boolean, required: false },
|
||||
showDvCompany: { type: Boolean, required: false, default: true }
|
||||
},
|
||||
emits: ['updateHeader'],
|
||||
setup( props, { emit } ) {
|
||||
|
||||
const $api = Vue.inject('$api');
|
||||
//const fhcAlert = Vue.inject('$fhcAlert');
|
||||
|
||||
|
||||
const readonly = Vue.ref(false);
|
||||
|
||||
const { t } = usePhrasen();
|
||||
|
||||
//const { personID: currentPersonID , personUID: currentPersonUID } = Vue.toRefs(props);
|
||||
const currentPersonID = Vue.computed(() => { return props.personID });
|
||||
const currentPersonUID = Vue.computed(() => { return props.personUID });
|
||||
|
||||
const dialogRef = Vue.ref();
|
||||
|
||||
const isFetching = Vue.ref(false);
|
||||
|
||||
const theModel = Vue.computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => emit('update:modelValue', value),
|
||||
});
|
||||
|
||||
const unternehmen = Vue.ref();
|
||||
const jobfunctionList = Vue.ref([]);
|
||||
const jobfunctionDefList = Vue.ref([]);
|
||||
const orgUnitList = Vue.ref([{value: '', label: '-'}]);
|
||||
|
||||
const aktivChecked = Vue.ref(true);
|
||||
|
||||
const table = Vue.ref(null); // reference to your table element
|
||||
const tabulator = Vue.ref(null); // variable to hold your table
|
||||
const tableData = Vue.reactive([]); // data for table to display
|
||||
|
||||
|
||||
const full = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
|
||||
const route = ( props.readonlyMode !== true ) ? VueRouter.useRoute() : null;
|
||||
|
||||
const convertArrayToObject = (array, key) => {
|
||||
const initialValue = {};
|
||||
return array.reduce((obj, item) => {
|
||||
return {
|
||||
...obj,
|
||||
[item[key]]: item,
|
||||
};
|
||||
}, initialValue);
|
||||
};
|
||||
|
||||
const fetchData = async () => {
|
||||
if (currentPersonID.value==null && theModel.value.personID==null) {
|
||||
jobfunctionList.value = [];
|
||||
return;
|
||||
}
|
||||
isFetching.value = true
|
||||
|
||||
// fetch data and map them for easier access
|
||||
try {
|
||||
const response = await $api.call(
|
||||
ApiFunktion.getAllUserFunctions(theModel.value.personUID || currentPersonUID.value));
|
||||
if(response.error === 1) {
|
||||
let rawList = [];
|
||||
tableData.value = [];
|
||||
jobfunctionList.value = convertArrayToObject(rawList, 'benutzerfunktion_id');
|
||||
} else {
|
||||
let rawList = response.retval;
|
||||
tableData.value = response.retval;
|
||||
jobfunctionList.value = convertArrayToObject(rawList, 'benutzerfunktion_id');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
isFetching.value = false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const createShape = () => {
|
||||
return {
|
||||
benutzerfunktion_id: 0,
|
||||
uid: theModel.value.personUID || currentPersonUID.value,
|
||||
oe_kurzbz: "",
|
||||
funktion_kurzbz: "",
|
||||
datum_von: "",
|
||||
datum_bis: "",
|
||||
bezeichnung: "",
|
||||
wochenstunden: 0,
|
||||
}
|
||||
}
|
||||
|
||||
const currentValue = Vue.ref(createShape());
|
||||
const preservedValue = Vue.ref(createShape());
|
||||
|
||||
Vue.watch([currentPersonID, currentPersonUID], ([id,uid]) => {
|
||||
fetchData();
|
||||
});
|
||||
|
||||
Vue.watch(unternehmen, (unternehmen_kurzbz) => {
|
||||
fetchOrgUnits(unternehmen_kurzbz);
|
||||
fetchFunctions();
|
||||
});
|
||||
|
||||
const toggleMode = async () => {
|
||||
if (!readonly.value) {
|
||||
// cancel changes?
|
||||
if (hasChanged.value) {
|
||||
const ok = await dialogRef.value.show();
|
||||
if (ok) {
|
||||
console.log("ok=", ok);
|
||||
currentValue.value = preservedValue.value;
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// switch to edit mode and preserve data
|
||||
preservedValue.value = {...currentValue.value};
|
||||
}
|
||||
readonly.value = !readonly.value;
|
||||
}
|
||||
|
||||
Vue.onMounted(async () => {
|
||||
currentValue.value = createShape();
|
||||
await fetchData();
|
||||
|
||||
const dateFormatter = (cell) => {
|
||||
return cell.getValue()?.replace(/(.*)-(.*)-(.*)/, '$3.$2.$1');
|
||||
}
|
||||
|
||||
const dvFormatter = (cell) => {
|
||||
if( props.readonlyMode === true ) {
|
||||
return (cell.getValue() != null) ? cell.getValue() : '';
|
||||
}
|
||||
const url = fullPath + route.params.id + '/' + route.params.uid + '/contract/' + cell.getRow().getData().dienstverhaeltnis_id;
|
||||
return cell.getValue() != null ? `<a href="${url}">` + cell.getValue() + '</a>' : '';
|
||||
}
|
||||
|
||||
// helper
|
||||
const createDomButton = (classValue, clickHandler) => {
|
||||
const nodeBtn = document.createElement("button");
|
||||
const classAttrBtn = document.createAttribute("class");
|
||||
classAttrBtn.value = "btn btn-outline-secondary btn-sm";
|
||||
nodeBtn.setAttributeNode(classAttrBtn);
|
||||
nodeBtn.addEventListener("click", clickHandler);
|
||||
const nodeI = document.createElement("i");
|
||||
const classAttrI = document.createAttribute("class");
|
||||
classAttrI.value = classValue;
|
||||
nodeI.setAttributeNode(classAttrI);
|
||||
nodeBtn.appendChild(nodeI);
|
||||
return nodeBtn;
|
||||
}
|
||||
|
||||
const btnFormatter = (cell) => {
|
||||
|
||||
const nodeDiv = document.createElement("div");
|
||||
const classAttrDiv = document.createAttribute("class");
|
||||
classAttrDiv.value = "d-grid gap-2 d-md-flex justify-content-end align-middle";
|
||||
nodeDiv.setAttributeNode(classAttrDiv);
|
||||
// delete button
|
||||
const nodeBtnDel = createDomButton("fa fa-xmark",() => { showDeleteModal(cell.getValue()) })
|
||||
// edit button
|
||||
const nodeBtnEdit = createDomButton("fa fa-pen",() => { showEditModal(cell.getValue()) })
|
||||
|
||||
if( cell.getRow().getData().dienstverhaeltnis_unternehmen === null ) {
|
||||
nodeDiv.appendChild(nodeBtnEdit);
|
||||
nodeDiv.appendChild(nodeBtnDel);
|
||||
}
|
||||
|
||||
return nodeDiv;
|
||||
}
|
||||
|
||||
|
||||
const columnsDef = [
|
||||
{ title: t('person','dv_unternehmen'), field: "dienstverhaeltnis_unternehmen", formatter: dvFormatter, sorter:"string", headerFilter:"list", headerFilterParams: {valuesLookup:true, autocomplete:true, sort:"asc"}, visible: props.showDvCompany },
|
||||
{ title: t('person','zuordnung_taetigkeit'), field: "funktion_beschreibung", hozAlign: "left", headerFilter:"list", headerFilterParams: {valuesLookup:true, autocomplete:true, sort:"asc"} },
|
||||
{ title: t('lehre','organisationseinheit'), field: "funktion_oebezeichnung", headerFilter:"list", headerFilterParams: {valuesLookup:true, autocomplete:true, sort:"asc"} },
|
||||
{ title: t('person','wochenstunden'), field: "wochenstunden", hozAlign: "right", width: 140, headerFilter:true },
|
||||
{ title: t('ui','from'), field: "datum_von", hozAlign: "center", formatter: dateFormatter, width: 140, sorter:"string", headerFilter:true, headerFilterFunc:customHeaderFilter },
|
||||
{ title: t('global','bis'), field: "datum_bis", hozAlign: "center", formatter: dateFormatter, width: 140, sorter:"string", headerFilter:true, headerFilterFunc:customHeaderFilter },
|
||||
{ title: t('ui','bezeichnung'), field: "bezeichnung", hozAlign: "left", headerFilter:"list", headerFilterParams: {valuesLookup:true, autocomplete:true, sort:"asc"} }
|
||||
];
|
||||
|
||||
if( props.readonlyMode === false) {
|
||||
columnsDef.push({ title: "", field: "benutzerfunktion_id", formatter: btnFormatter, hozAlign: "right", width: 100, headerSort: false, frozen: true });
|
||||
}
|
||||
|
||||
let tabulatorOptions = {
|
||||
height: "100%",
|
||||
layout: "fitColumns",
|
||||
movableColumns: true,
|
||||
reactiveData: true,
|
||||
columns: columnsDef,
|
||||
//data: tableData.value,
|
||||
data: jobfunctionListArray.value,
|
||||
};
|
||||
|
||||
tabulator.value = new Tabulator(
|
||||
table.value,
|
||||
tabulatorOptions
|
||||
);
|
||||
|
||||
function customHeaderFilter(headerValue, rowValue, rowData, filterParams){
|
||||
//headerValue - the value of the header filter element
|
||||
//rowValue - the value of the column in this row
|
||||
//rowData - the data for the row being filtered
|
||||
//filterParams - params object passed to the headerFilterFuncParams property
|
||||
|
||||
const validDate = function(d){
|
||||
return d instanceof Date && isFinite(d);
|
||||
}
|
||||
|
||||
const date1 = new Date(rowValue);
|
||||
date1.setHours(0,0,0,0);
|
||||
let [day, month, year] = headerValue.split('.')
|
||||
if (year < 1000) return true; // prevents dates like 17.5.2
|
||||
const date2 = new Date(+year, +month - 1, +day);
|
||||
|
||||
return !(validDate(date2)) || ((date2 - date1) == 0); //must return a boolean, true if it passes the filter.
|
||||
}
|
||||
|
||||
tabulator.value.on('tableBuilt', () => {
|
||||
//tabulator.value.setData(tableData.value);
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
const jobfunctionListArray = Vue.computed(() => {
|
||||
let temp = (jobfunctionList.value ? Object.values(jobfunctionList.value) : []);
|
||||
let filtered = temp.filter((e) => ( !aktivChecked.value || (aktivChecked.value && e.aktiv) ));
|
||||
return filtered;
|
||||
});
|
||||
|
||||
// Workaround to update tabulator
|
||||
Vue.watch(jobfunctionListArray, (newVal, oldVal) => {
|
||||
console.log('jobfunctionList changed');
|
||||
tabulator.value?.setData(jobfunctionListArray.value);
|
||||
}, {deep: true})
|
||||
|
||||
// Modal
|
||||
const modalRef = Vue.ref();
|
||||
const confirmDeleteRef = Vue.ref();
|
||||
|
||||
const showAddModal = () => {
|
||||
currentValue.value = createShape();
|
||||
// reset form state
|
||||
frmState.orgetBlurred=false;
|
||||
frmState.funktionBlurred=false;
|
||||
frmState.beginnBlurred=false;
|
||||
// call bootstrap show function
|
||||
modalRef.value.show();
|
||||
}
|
||||
|
||||
const hideModal = () => {
|
||||
modalRef.value.hide();
|
||||
}
|
||||
|
||||
const showEditModal = async (id) => {
|
||||
currentValue.value = { ...jobfunctionList.value[id] };
|
||||
// fetch company
|
||||
isFetching.value = true;
|
||||
try {
|
||||
const res = await $api.call(ApiFunktion.getCompanyByOrget(currentValue.value.oe_kurzbz));
|
||||
if (res.error == 0) {
|
||||
unternehmen.value = res.retval[0].oe_kurzbz;
|
||||
} else {
|
||||
console.log('company not found for orget!');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
isFetching.value = false
|
||||
}
|
||||
//delete currentValue.value.bezeichnung;
|
||||
modalRef.value.show();
|
||||
}
|
||||
|
||||
const showDeleteModal = async (id) => {
|
||||
currentValue.value = { ...jobfunctionList.value[id] };
|
||||
const ok = await confirmDeleteRef.value.show();
|
||||
|
||||
if (ok) {
|
||||
|
||||
try {
|
||||
const res = await $api.call(ApiPerson.deletePersonJobFunction(id));
|
||||
if (res.error == 0) {
|
||||
delete jobfunctionList.value[id];
|
||||
showDeletedToast();
|
||||
theModel.value.updateHeader();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
isFetching.value = false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const okHandler = async () => {
|
||||
if (!validate()) {
|
||||
|
||||
console.log("form invalid");
|
||||
|
||||
} else {
|
||||
|
||||
// submit
|
||||
try {
|
||||
let payload = {...currentValue.value};
|
||||
delete payload.dienstverhaeltnis_id;
|
||||
delete payload.dienstverhaeltnis_unternehmen;
|
||||
delete payload.fachbereich_bezeichnung;
|
||||
delete payload.funktion_oebezeichnung;
|
||||
delete payload.aktiv;
|
||||
delete payload.funktion_beschreibung;
|
||||
const r = await $api.call(ApiPerson.upsertPersonJobFunction(payload));
|
||||
if (r.error == 0) {
|
||||
// fetch all data because of all the references in the changed record
|
||||
await fetchData();
|
||||
console.log('job function successfully saved');
|
||||
theModel.value.updateHeader();
|
||||
showToast();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
} finally {
|
||||
isFetching.value = false
|
||||
}
|
||||
|
||||
hideModal();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------
|
||||
// form handling
|
||||
// -------------
|
||||
|
||||
const jobFunctionFrm = Vue.ref();
|
||||
|
||||
const frmState = Vue.reactive({ beginnBlurred: false, orgetBlurred: false, funktionBlurred: false, wasValidated: false });
|
||||
|
||||
const notEmpty = (n) => {
|
||||
return !!n && n.trim() != "";
|
||||
}
|
||||
|
||||
const validate = () => {
|
||||
frmState.orgetBlurred = true;
|
||||
frmState.funktionBlurred = true;
|
||||
frmState.beginnBlurred = true;
|
||||
return notEmpty(currentValue.value.datum_von) &&
|
||||
notEmpty(currentValue.value.oe_kurzbz) &&
|
||||
notEmpty(currentValue.value.funktion_kurzbz);
|
||||
}
|
||||
|
||||
|
||||
const hasChanged = Vue.computed(() => {
|
||||
return Object.keys(currentValue.value).some(field => currentValue.value[field] !== preservedValue.value[field])
|
||||
});
|
||||
|
||||
const formatDate = (d) => {
|
||||
if (d != null && d != '') {
|
||||
return d.substring(8, 10) + "." + d.substring(5, 7) + "." + d.substring(0, 4);
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
// Toast
|
||||
const toastRef = Vue.ref();
|
||||
const deleteToastRef = Vue.ref();
|
||||
|
||||
const showToast = () => {
|
||||
toastRef.value.show();
|
||||
}
|
||||
|
||||
const showDeletedToast = () => {
|
||||
deleteToastRef.value.show();
|
||||
}
|
||||
|
||||
const fetchOrgUnits = async (unternehmen_kurzbz) => {
|
||||
if( unternehmen_kurzbz === '' ) {
|
||||
return;
|
||||
}
|
||||
const response = await $api.call(
|
||||
ApiFunktion.getOrgetsForCompany(unternehmen_kurzbz));
|
||||
const orgets = response.retval;
|
||||
orgets.unshift({
|
||||
value: '',
|
||||
label: t('ui','bitteWaehlen'),
|
||||
});
|
||||
orgUnitList.value = await orgets;
|
||||
}
|
||||
|
||||
const fetchFunctions = async (uid, unternehmen_kurzbz) => {
|
||||
if(unternehmen_kurzbz === '' || uid === '' ) {
|
||||
return;
|
||||
}
|
||||
const response = await $api.call(ApiFunktion.getAllFunctions());
|
||||
const benutzerfunktionen = response.retval;
|
||||
benutzerfunktionen.unshift({
|
||||
value: '',
|
||||
label: t('ui','bitteWaehlen'),
|
||||
});
|
||||
jobfunctionDefList.value = benutzerfunktionen;
|
||||
}
|
||||
|
||||
const unternehmenSelectedHandler = (e) => {
|
||||
console.log('unternehmen selected: ',e);
|
||||
unternehmen.value = e;
|
||||
}
|
||||
|
||||
const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
|
||||
const fullPath = `/${ciPath}/extensions/FHC-Core-Personalverwaltung/Employees/`;
|
||||
|
||||
return {
|
||||
jobfunctionList, orgUnitList, jobfunctionListArray,
|
||||
jobfunctionDefList,
|
||||
currentValue,
|
||||
readonly,
|
||||
frmState,
|
||||
dialogRef,
|
||||
toastRef, deleteToastRef,
|
||||
jobFunctionFrm,
|
||||
modalRef,
|
||||
fullPath,
|
||||
route,
|
||||
aktivChecked,
|
||||
unternehmen,
|
||||
tabulator,
|
||||
table,
|
||||
|
||||
toggleMode, formatDate, notEmpty,
|
||||
showToast, showDeletedToast,
|
||||
showAddModal, hideModal, okHandler,
|
||||
showDeleteModal, showEditModal, confirmDeleteRef, t, unternehmenSelectedHandler
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="row" v-if="readonlyMode === false">
|
||||
|
||||
<div class="toast-container position-absolute top-0 end-0 pt-4 pe-2">
|
||||
<Toast ref="toastRef">
|
||||
<template #body><h4>{{ t('person','funktionGespeichert') }}</h4></template>
|
||||
</Toast>
|
||||
</div>
|
||||
|
||||
<div class="toast-container position-absolute top-0 end-0 pt-4 pe-2">
|
||||
<Toast ref="deleteToastRef">
|
||||
<template #body><h4>{{ t('person', 'funktionGeloescht') }}</h4></template>
|
||||
</Toast>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row pt-md-4">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="h5"><h5>{{ t('person','funktionen') }}</h5></div>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<div class="d-grid d-md-flex justify-content-between pt-2 pb-3" v-if="readonlyMode === false">
|
||||
<button type="button" class="btn btn-sm btn-primary me-3" @click="showAddModal()">
|
||||
<i class="fa fa-plus"></i> {{ t('person','funktion') }}
|
||||
</button>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="aktivChecked" v-model="aktivChecked">
|
||||
<label class="form-check-label" for="aktivChecked">Nur aktive anzeigen</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TABULATOR -->
|
||||
<div ref="table" class="fhc-tabulator"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- detail modal -->
|
||||
<Modal :title="t('person','funktion')" ref="modalRef" v-if="readonlyMode === false">
|
||||
<template #body>
|
||||
<form class="row g-3" ref="jobFunctionFrm">
|
||||
|
||||
<div class="col-md-8">
|
||||
<div v-show="showDvCompany">
|
||||
<label class="form-label">{{ t('core','unternehmen') }}</label><br>
|
||||
<org-chooser @org-selected="unternehmenSelectedHandler" :oe="unternehmen" class="form-select form-select-sm"></org-chooser>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
</div>
|
||||
<!-- -->
|
||||
<div class="col-md-8">
|
||||
<label class="required form-label">{{ t('lehre','organisationseinheit') }}</label><br>
|
||||
<select id="oe_kurzbz" v-model="currentValue.oe_kurzbz"
|
||||
@blur="frmState.orgetBlurred = true"
|
||||
class="form-select form-select-sm" aria-label=".form-select-sm "
|
||||
:class="{ 'form-control-plaintext': readonly, 'form-control': !readonly, 'is-invalid': !notEmpty(currentValue.oe_kurzbz) && frmState.orgetBlurred}"
|
||||
>
|
||||
<option v-for="(item, index) in orgUnitList" :value="item.value">
|
||||
{{ item.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
</div>
|
||||
<!-- -->
|
||||
<div class="col-md-8">
|
||||
<label for="funktion_kurzbz" class="required form-label">{{ t('person','funktion') }}</label><br>
|
||||
<select id="_kurzbz" v-model="currentValue.funktion_kurzbz"
|
||||
@blur="frmState.funktionBlurred = true"
|
||||
class="form-select form-select-sm" aria-label=".form-select-sm "
|
||||
:class="{ 'form-control-plaintext': readonly, 'form-control': !readonly, 'is-invalid': !notEmpty(currentValue.funktion_kurzbz) && frmState.funktionBlurred}"
|
||||
>
|
||||
<option v-for="(item, index) in jobfunctionDefList" :value="item.value">
|
||||
{{ item.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4"></div>
|
||||
<!-- -->
|
||||
<div class="col-md-2">
|
||||
<label for="uid" class="form-label">{{ t('person','wochenstunden') }}</label>
|
||||
<input type="number" :readonly="readonly" class="form-control-sm" :class="{ 'form-control-plaintext': readonly, 'form-control': !readonly}" id="bank" v-model="currentValue.wochenstunden">
|
||||
</div>
|
||||
<!-- -->
|
||||
<div class="col-md-3">
|
||||
<label for="beginn" class="required form-label">{{ t('ui','from') }}</label>
|
||||
<datepicker id="beginn"
|
||||
:teleport="true"
|
||||
@blur="frmState.beginnBlurred = true"
|
||||
:input-class-name="(!notEmpty(currentValue.datum_von) && frmState.beginnBlurred) ? 'dp-invalid-input' : ''"
|
||||
v-model="currentValue.datum_von"
|
||||
v-bind:enable-time-picker="false"
|
||||
text-input
|
||||
locale="de"
|
||||
format="dd.MM.yyyy"
|
||||
auto-apply
|
||||
model-type="yyyy-MM-dd"></datepicker>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="ende" class="form-label">{{ t('global','bis') }}</label>
|
||||
<datepicker id="ende"
|
||||
:teleport="true"
|
||||
v-model="currentValue.datum_bis"
|
||||
v-bind:enable-time-picker="false"
|
||||
text-input
|
||||
locale="de"
|
||||
format="dd.MM.yyyy"
|
||||
auto-apply
|
||||
model-type="yyyy-MM-dd"></datepicker>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
</div>
|
||||
<!-- -->
|
||||
<div class="col-md-8">
|
||||
<label for="bezeichnung" class="form-label">{{ t('ui','bezeichnung') }}</label>
|
||||
<input type="text" :readonly="readonly" class="form-control-sm" :class="{ 'form-control-plaintext': readonly, 'form-control': !readonly}" id="bezeichnung" v-model="currentValue.bezeichnung">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
</div>
|
||||
|
||||
|
||||
<!-- changes -->
|
||||
<div class="col-8">
|
||||
<div class="modificationdate">{{ currentValue.insertamum }}/{{ currentValue.insertvon }}, {{ currentValue.updateamum }}/{{ currentValue.updatevon }} [id={{ currentValue.benutzerfunktion_id }}]</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</template>
|
||||
<template #footer>
|
||||
<button type="button" class="btn btn-primary" @click="okHandler()" >
|
||||
{{ t('ui','speichern') }}
|
||||
</button>
|
||||
</template>
|
||||
|
||||
</Modal>
|
||||
|
||||
<ModalDialog :title="t('global','warnung')" ref="dialogRef" v-if="readonlyMode === false">
|
||||
<template #body>
|
||||
{{ t('person','funktionNochNichtGespeichert') }}
|
||||
</template>
|
||||
</ModalDialog>
|
||||
|
||||
<ModalDialog :title="t('global','warnung')" ref="confirmDeleteRef" v-if="readonlyMode === false">
|
||||
<template #body>
|
||||
{{ t('person','funktion') }} '{{ currentValue?.funktion_kurzbz }} ({{ currentValue?.datum_von }}-{{ currentValue?.datum_bis }})' {{ t('person', 'wirklichLoeschen') }}?
|
||||
</template>
|
||||
</ModalDialog>
|
||||
`
|
||||
}
|
||||
|
||||
export default Funktionen;
|
||||
@@ -9,16 +9,17 @@ export default {
|
||||
},
|
||||
template: `
|
||||
<div class="stv-details-functions h-100 d-flex flex-column">
|
||||
<table-functions
|
||||
ref="tbl_functions"
|
||||
:student="modelValue">
|
||||
</table-functions>
|
||||
<h4>{{ $p.t('person', 'funktionen') }}</h4>
|
||||
|
||||
<person-functions
|
||||
:readonlyMode="false"
|
||||
:personID="modelValue.person_id"
|
||||
:personUID="modelValue.uid"
|
||||
:showDvCompany="false"
|
||||
:showDvCompany="true"
|
||||
:saveFunctionAsCopy="true"
|
||||
:filterOeStudent="true"
|
||||
:oeDropdownAutocomplete="true"
|
||||
:stylePv21="false"
|
||||
>
|
||||
</person-functions>
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import PersonFunctions from "../../../Funktionen/Funktionen_composition_api";
|
||||
|
||||
//import PersonFunctions from "../../../Funktionen/Funktionen.js";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PersonFunctions,
|
||||
},
|
||||
props: {
|
||||
modelValue: Object,
|
||||
},
|
||||
template: `
|
||||
<div class="stv-details-functions h-100 d-flex flex-column">
|
||||
<table-functions
|
||||
ref="tbl_functions"
|
||||
:student="modelValue">
|
||||
</table-functions>
|
||||
|
||||
<person-functions
|
||||
:readonlyMode="false"
|
||||
:personID="modelValue.person_id"
|
||||
:personUID="modelValue.uid"
|
||||
:showDvCompany="true"
|
||||
>
|
||||
</person-functions>
|
||||
|
||||
</div>`,
|
||||
};
|
||||
+101
-1
@@ -25079,7 +25079,7 @@ array(
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Das Eingabefeld {field} darf nur Zahlen enthalten.',
|
||||
'text' => 'Das Eingabefeld {field} darf nur Ziffern enthalten.',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
@@ -41476,6 +41476,106 @@ and represent the current state of research on the topic. The prescribed citatio
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'funktion',
|
||||
'phrase' => 'filter_active',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Nur aktive anzeigen',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Display only active',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'funktion',
|
||||
'phrase' => 'addFunktion',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Funktion hinzufügen',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Add function',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'funktion',
|
||||
'phrase' => 'editFunktion',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Funktion bearbeiten',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Edit function',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'saveAsCopy',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Als Kopie speichern',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Save as copy',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'error_fieldMustBePositiveInteger',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Das Eingabefeld {field} darf nur positive Ganzzahlen enthalten.',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'The input field {field} may only contain positive integers',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
// FHC-4 Studierendenverwaltung FUNCTIONS END
|
||||
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user