Refactoring PrimeVue Autocomplete Dropdown Functions

Refactoring PrimeVue Autocomplete Dropdown OrganisationUnits
Change Search from Backend to Frontend Filtering
minor changes Table Functions
This commit is contained in:
ma0068
2025-05-23 13:27:18 +02:00
parent 66e5384de6
commit fa0b534471
6 changed files with 162 additions and 216 deletions
@@ -11,14 +11,10 @@ class Funktionen extends FHCAPI_Controller
//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'],
'getAllOrgUnits' => ['admin:r', 'assistenz:r'],
'loadFunction' => ['admin:r', 'assistenz:r'],
'insertFunction' => ['admin:rw', 'assistenz:rw'],
'updateFunction' => ['admin:rw', 'assistenz:rw'],
@@ -43,6 +39,20 @@ class Funktionen extends FHCAPI_Controller
$this->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel');
}
public function getAllFunctions()
{
$this->FunktionModel->addSelect("funktion_kurzbz");
$this->FunktionModel->addSelect("beschreibung");
$this->FunktionModel->addSelect("aktiv");
$this->FunktionModel->addSelect("beschreibung AS label");
$this->FunktionModel->addOrder("beschreibung");
$result = $this->FunktionModel->load();
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
public function getOrgHeads()
{
$result = $this->OrganisationseinheitModel->getHeads();
@@ -97,7 +107,7 @@ class Funktionen extends FHCAPI_Controller
WHERE
bf.uid = ?
ORDER BY
f.beschreibung, bf.datum_von ASC";
bf.datum_von, bf.datum_von ASC";
$benutzerfunktionen = $this->BenutzerfunktionModel->execReadOnlyQuery($sql, array($uid));
$data = $this->getDataOrTerminateWithError($benutzerfunktionen);
@@ -106,14 +116,35 @@ class Funktionen extends FHCAPI_Controller
}
/*
* return list of child orgets for a given company orget_kurzbz
* returns list of all organisation units
* as key value list to be used in select or autocomplete
*/
public function getOrgetsForCompany($companyOrgetkurzbz=null)
public function getAllOrgUnits()
{
$sql = "
SELECT
oe.oe_kurzbz,
oe.oe_kurzbz, oe.aktiv,
'[' || COALESCE(oet.bezeichnung, oet.organisationseinheittyp_kurzbz) ||
'] ' || COALESCE(oe.bezeichnung, oe.oe_kurzbz) AS label
FROM public.tbl_organisationseinheit oe
JOIN public.tbl_organisationseinheittyp oet ON oe.organisationseinheittyp_kurzbz = oet.organisationseinheittyp_kurzbz
ORDER BY oet.bezeichnung ASC, oe.bezeichnung ASC";
$result = $this->OrganisationseinheitModel->execReadOnlyQuery($sql);
$data = $this->getDataOrTerminateWithError($result);
$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, oe.aktiv,
'[' || COALESCE(oet.bezeichnung, oet.organisationseinheittyp_kurzbz) ||
'] ' || COALESCE(oe.bezeichnung, oe.oe_kurzbz) AS label
FROM (
@@ -139,25 +170,6 @@ class Funktionen extends FHCAPI_Controller
$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("*");
@@ -191,7 +191,7 @@ class Organisationseinheit_model extends DB_Model
/**
* @param string $oe_kurzbz
*
*
* @return stdClass
*/
public function getWithType($oe_kurzbz)
@@ -202,78 +202,6 @@ class Organisationseinheit_model extends DB_Model
return $this->load($oe_kurzbz);
}
/**
* Get OEs by eventQuery string. Use with autocomplete event queries.
* @param $eventQuery String
* @return array
*/
public function getAutocompleteSuggestions($eventQuery)
{
$this->addSelect('oe_kurzbz');
$this->addSelect('organisationseinheittyp_kurzbz, oe_kurzbz, bezeichnung, aktiv, lehre');
$this->addOrder('organisationseinheittyp_kurzbz, bezeichnung');
return $this->loadWhere("
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
*/
@@ -11,26 +11,4 @@ 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). "%'
");
}
}
+2 -37
View File
@@ -15,17 +15,6 @@
* 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 {
@@ -41,30 +30,13 @@ export default {
url,
};
},
loadAllOes(filterStudent) {
var url = 'api/frontend/v1/funktionen/Funktionen/loadAllOes'
+ '/' + filterStudent;
getAllOrgUnits(filterStudent) {
var url = 'api/frontend/v1/funktionen/Funktionen/getAllOrgUnits';
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;
@@ -114,11 +86,4 @@ export default {
url: 'api/frontend/v1/funktionen/Funktionen/searchOes/' + head + '/' + searchString
};
},
getFunctions(searchString) {
return {
method: 'get',
url: 'api/frontend/v1/funktionen/Funktionen/searchFunctions/' + searchString
};
}
};
+99 -56
View File
@@ -43,10 +43,8 @@ export default {
{
title: "dienstverhaeltnis_unternehmen",
field: "dienstverhaeltnis_unternehmen",
width: 50,
headerFilter: "list",
headerFilterParams: {valuesLookup: true, autocomplete: true, sort: "asc"},
formatter: this.companyLinkFormatter
},
{
title: "funktion_beschreibung", field: "funktion_beschreibung", headerFilter: "list",
@@ -100,7 +98,6 @@ export default {
let container = document.createElement('div');
container.className = "d-flex gap-2";
if( cell.getRow().getData().dienstverhaeltnis_unternehmen === null ) {
let button = document.createElement('button');
button.className = 'btn btn-outline-secondary btn-action';
@@ -160,18 +157,19 @@ export default {
const column = cm.getColumnByField('dienstverhaeltnis_unternehmen');
const companyDv = {
title: this.$p.t('person', 'dv_unternehmen'),
width: 100,
width: 140,
visible: this.showDvCompany,
formatter: this.companyLinkFormatter
};
column.component.updateDefinition(companyDv);
cm.getColumnByField('funktion_beschreibung').component.updateDefinition({
title: this.$p.t('person', 'zuordnung_taetigkeit'),
width: 100
width: 140
});
cm.getColumnByField('funktion_oebezeichnung').component.updateDefinition({
title: this.$p.t('lehre', 'organisationseinheit'),
width: 100
width: 140
});
cm.getColumnByField('wochenstunden').component.updateDefinition({
title: this.$p.t('person', 'wochenstunden')
@@ -192,18 +190,25 @@ export default {
cm.getColumnByField('bezeichnung').component.updateDefinition({
title: this.$p.t('ui', 'bezeichnung'),
width: 100
width: 140
});
}
}
],
isFilterSet: false,
isFilterSet: true,
listOrgHeads: [],
listOrgUnits: [],
listOrgUnits: [], //Old
listAllOrgUnits: [],
listOrgUnits_GST: [],
listOrgUnits_GMBH: [],
formData: {
head: 'gst',
oe_kurzbz: ''
oe_kurzbz: '',
funktion_kurzbz: null,
label:'',
//funktion_label: '',
funktion: null,
},
statusNew: true,
listAllFunctions: [],
@@ -213,7 +218,17 @@ export default {
},
filteredOes: [],
filteredFunctions: [],
newBtnStyle: ''
newBtnStyle: '',
selectedFunction: null,
selectedOe: null
}
},
watch: {
selectedFunction(newVal) {
this.formData.funktion_kurzbz = newVal?.funktion_kurzbz || '';
},
selectedOe(newVal) {
this.formData.oe_kurzbz = newVal?.oe_kurzbz || '';
}
},
methods: {
@@ -229,6 +244,7 @@ export default {
actionNewFunction(){
this.resetModal();
this.statusNew = true;
this.formData.datum_von = new Date();
this.$refs.functionModal.show();
},
actionCopyFunction(benutzerfunktion_id) {
@@ -249,7 +265,15 @@ export default {
actionEditFunction(benutzerfunktion_id) {
this.resetModal();
this.statusNew = false;
this.loadFunction(benutzerfunktion_id);
this.loadFunction(benutzerfunktion_id).then(() => {
//set selectedFunction and selectedOd to enable viewing label in primevue autocomplete fields
this.selectedFunction = this.listAllFunctions.find(
item => item.funktion_kurzbz === this.formData.funktion_kurzbz
);
this.selectedOe = this.listAllOrgUnits.find(
item => item.oe_kurzbz === this.formData.oe_kurzbz
);
});
this.$refs.functionModal.show();
},
addFunction() {
@@ -304,14 +328,6 @@ export default {
this.reload();
});
},
getOrgetsForCompany(){
return this.$api
.call(ApiCoreFunktion.getOrgetsForCompany(this.formData.head))
.then(result => {
this.listOrgUnits = result.data;
})
.catch(this.$fhcAlert.handleSystemError);
},
hideModal(modalRef) {
this.$refs[modalRef].hide();
},
@@ -324,32 +340,30 @@ export default {
this.formData.oe_kurzbz = '';
this.formData.funktion_kurzbz = '';
},
searchOe(event) {
if (this.abortController.oes) {
this.abortController.oes.abort();
}
this.abortController.oes = new AbortController();
return this.$api
.call(ApiCoreFunktion.getOes(this.formData.head, event.query))
.then(result => {
this.filteredOes = result.data.retval;
});
filterFunctions(event) {
const query = event.query.toLowerCase();
this.filteredFunctions = this.listAllFunctions.filter(item =>
item.label.toLowerCase().includes(query)
)
},
searchFunctions(event) {
if (this.abortController.functions) {
this.abortController.functions.abort();
filterOes(event) {
const query = event.query.toLowerCase();
if(!this.formData.head)
this.$fhcAlert.alertError(this.$p.t('ui', 'bitteUnternehmenWaehlen'));
if(this.formData.head == 'gst') {
this.filteredOes = this.listOrgUnits_GST.filter(item =>
item.label.toLowerCase().includes(query)
);
}
if(this.formData.head == 'gmbh') {
this.filteredOes = this.listOrgUnits_GMBH.filter(item =>
item.label.toLowerCase().includes(query)
);
}
this.abortController.functions = new AbortController();
return this.$api
.call(ApiCoreFunktion.getFunctions(event.query))
.then(result => {
this.filteredFunctions = result.data.retval;
});
},
styleNewButton(){
if(this.stylePv21) {
this.newBtnStyle = "btn-sm";
@@ -370,12 +384,38 @@ export default {
})
.catch(this.$fhcAlert.handleSystemError);
this.$api
.call(ApiCoreFunktion.getAllFunctions())
.then(result => {
this.listAllFunctions = result.data;
})
.catch(this.$fhcAlert.handleSystemError);
this.$api
.call(ApiCoreFunktion.getAllOrgUnits())
.then(result => {
this.listAllOrgUnits = result.data;
})
.catch(this.$fhcAlert.handleSystemError);
this.$api
.call(ApiCoreFunktion.getOrgetsForCompany('gst'))
.then(result => {
this.listOrgUnits_GST = result.data;
})
.catch(this.$fhcAlert.handleSystemError);
this.$api
.call(ApiCoreFunktion.getOrgetsForCompany('gmbh'))
.then(result => {
this.listOrgUnits_GMBH = result.data;
})
.catch(this.$fhcAlert.handleSystemError);
this.styleNewButton();
},
template: `
<div class="core-functions h-100 pb-3">
<div class="d-flex justify-content-end pb-3" v-if="stylePv21">
<div class="d-flex justify-content-end" v-if="stylePv21">
<form-input
container-class="form-check"
type="checkbox"
@@ -418,35 +458,37 @@ export default {
</template>
<form-form class="row pt-3" ref="functionData">
<form-input
container-class="mb-3 col-8"
type="select"
name="companies"
:label="$p.t('core/unternehmen')"
v-model="formData.head"
@change="getOrgetsForCompany"
@change="getOrgetsForCompanyOld"
>
<option
v-for="org in listOrgHeads"
:key="org.head"
:value="org.head"
@change="handleChange"
>
{{ org.bezeichnung }}
</option>
</form-input>
</form-input>
<!--DropDown Autocomplete Funktion-->
<!--DropDown Autocomplete Funktion -->
<form-input
container-class="mb-3 col-8"
type="autocomplete"
:label="$p.t('person/funktion') + ' *' "
name="funktion_kurzbz"
v-model="formData.funktion_kurzbz"
v-model="selectedFunction"
forceSelection
optionLabel="label"
optionValue="funktion_kurzbz"
:suggestions="filteredFunctions"
dropdown
@complete="searchFunctions"
@complete="filterFunctions"
>
<template #option="slotProps">
<div
@@ -454,7 +496,7 @@ export default {
? 'item-inactive'
: ''"
>
{{slotProps.option.label}}
{{ slotProps.option.label}}
</div>
</template>
</form-input>
@@ -465,11 +507,13 @@ export default {
type="autocomplete"
:label="$p.t('lehre/organisationseinheit') + ' *'"
name="oe_kurzbz"
v-model="formData.oe_kurzbz"
v-model="selectedOe"
forceSelection
optionLabel="label"
optionValue="oe_kurzbz"
:suggestions="filteredOes"
dropdown
@complete="searchOe"
@complete="filterOes"
>
<template #option="slotProps">
<div
@@ -482,7 +526,6 @@ export default {
</template>
</form-input>
<!--DropDown Bezeichnung-->
<form-input
container-class="mb-3 col-8"
type="text"
@@ -531,7 +574,7 @@ export default {
>
</form-input>
</div>
<input type="hidden" class="form-control" id="oe_kurzbz" v-model="formData.oe_kurzbz">
</form-form>
+20
View File
@@ -41576,6 +41576,26 @@ and represent the current state of research on the topic. The prescribed citatio
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'bitteUnternehmenWaehlen',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Vor Änderung der Organisationseinheit bitte Unternehmen wählen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Before changing the organizational unit, please select company',
'description' => '',
'insertvon' => 'system'
)
)
),
// FHC-4 Studierendenverwaltung FUNCTIONS END
);