Merge branch 'master' into feature-13011/installation_on_multiple_servers

This commit is contained in:
Paolo
2023-03-21 17:47:15 +01:00
1135 changed files with 31146 additions and 100447 deletions
+66
View File
@@ -0,0 +1,66 @@
.filter-header-title {
text-align: right;
}
.filter-header-title-span-filter {
margin-right: 7px;
}
.filter-header-title-span-icon {
margin-right: 3px;
cursor: pointer;
}
.filter-options-div {
padding: 10px;
}
.filter-fields-area {
height: 50px;
padding: 3px;
margin-bottom: 10px;
}
.filter-fields-field {
height: 100%;
margin-left: 7px;
padding: 11px;
display: inline-block;
background-color: white;
border-style: solid;
border-color: black;
border-width: 1px;
border-radius: 7px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
cursor: pointer;
}
.filter-filter-fields {
margin-top: 12px;
margin-bottom: 12px;
}
.selection-before::before {
content: "";
position: absolute;
top: 0;
right: 100%;
height: 100%;
margin-right: 3px;
border-left: 2px solid #428bca;
}
.selection-after::after {
content: "";
position: absolute;
top: 0;
left: 100%;
height: 100%;
margin-left: 3px;
border-right: 2px solid #428bca;
}
.filter-table-dataset {
margin-top: 20px;
}
@@ -0,0 +1,90 @@
/*
* Hederer
*/
.navbar-header {
background-color: #f8f8f8;
padding-top: 0px;
padding-bottom: 0px;
padding-left: 10px;
border-style: solid;
border-color: #e7e7e7;
border-width: 0 0 1px;
}
.header-menu-link-entry {
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 18px;
line-height: 1.42857143;
color: #5e5e5e !important;
padding-top: 15px !important;
padding-right: 7px !important;
padding-left: 7px !important;
}
.header-menu-icon {
top: 0px;
margin-right: 3px;
font-size: 16px;
}
/*
* Left side
*/
.navbar-left-side {
z-index: 1;
position: absolute;
width: 250px;
border-right: 1px solid #e7e7e7;
background-color: #f8f8f8;
}
.navbar-left-side ul {
width: 250px;
}
.navbar-left-side ul li {
border-bottom: 1px solid #e7e7e7;
}
.left-side-menu-second-level {
padding-top: 0px !important;
padding-bottom: 0px !important;
}
.left-side-menu-second-level li {
border-bottom: none !important;
}
.left-side-menu-second-level span {
display: inline-flex;
}
.remove-custom-filter {
font-size: 10px !important;
}
.left-side-menu-link-entry {
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 14px;
line-height: 1.42857143;
color: #23527c;
padding-top: 10px !important;
padding-bottom: 10px !important;
padding-left: 7px !important;
padding-right: 7px !important;
text-decoration: none;
}
.left-side-menu-link-entry:hover {
background-color: #eee;
}
/*
* To be moved outside
*/
#content {
position: inherit;
margin: 0 0 0 250px;
padding: 30px 30px;
}
+90
View File
@@ -0,0 +1,90 @@
/*
Created on : Jun 15, 2022, 3:21:25 PM
Author : bambi
*/
.searchbar_settings {
position: absolute;
z-index: 9999;
background-color: #fff;
border: 2px solid #666;
padding: 1rem;
}
.searchbar_results {
position: absolute;
z-index: 9998;
background-color: #fff;
border: 2px solid #666;
padding: 1rem;
overflow-y: auto;
}
.searchbar_result {
border-bottom: 1px solid #666;
margin-bottom: 1rem;
}
.searchbar_grid {
display: grid;
grid-template-columns: [icon] 100px [data] auto;
}
.searchbar_icon {
grid-column-start: icon;
grid-column-end: span 1;
}
.searchbar_data {
grid-column-start: data;
grid-column-end: span 1;
}
.searchbar_actions {
display: flex;
padding: 0;
margin-top: 1rem;
}
.searchbar_actions li {
list-style: none;
text-align: center;
padding: 3px;
}
.searchbar_table {
display: table;
}
.searchbar_tablerow {
display: table-row;
}
.searchbar_tablecell {
display: table-cell;
min-width: 175px;
padding: 0 6px;
}
.searchbar_settings_types {
display: flex;
padding: 0;
}
.searchbar_settings_types li {
list-style: none;
padding: 5px;
}
.searchbar_settings_types li label {
padding: 3px;
}
.searchbar_inline_ul {
margin: 0;
padding: 0;
}
.searchbar_inline_ul li {
list-style: none;
}
+59
View File
@@ -0,0 +1,59 @@
/*
Created on : May 19, 2022, 10:16:21 AM
Author : bambi
*/
:root {
--fhc-verticalsplit-vsplitter-bg-color: #eee;
--fhc-verticalsplit-vsplitter-border-color: #eee;
--fhc-verticalsplit-vsplitter-splitactions-color: #000;
}
.verticalsplitted {
overflow-y: auto;
}
.verticalsplitter {
text-align: center;
}
.verticalsplitter.top {
border-top: solid 3px var(--fhc-verticalsplit-vsplitter-border-color);
}
.verticalsplitter.bottom {
border-bottom: solid 3px var(--fhc-verticalsplit-vsplitter-border-color);
}
.splitactions {
background-color: var(--fhc-verticalsplit-vsplitter-bg-color);
color: var(--fhc-verticalsplit-vsplitter-splitactions-color);
display: inline-block;
padding: 0 5px 0 5px;
}
.splitactions.top {
border-radius: 0 0 40% 40%;
}
.splitactions.bottom {
border-radius: 40% 40% 0 0;
}
.splitaction {
display: inline-block;
width: 25px;
cursor: pointer;
}
.splitaction.resize {
cursor: row-resize;
}
#content {
padding-top: 0 !important;
padding-bottom: 0 !important;
}
#content > div:first-child {
margin-top: 30px;
}
@@ -104,3 +104,7 @@
display: inline-block
}
}
.gesperrtoption {
color: gray;
}
@@ -0,0 +1,13 @@
td.tableCellNoRightBorder {
border-right: 0 !important;
}
td.tableCellNoLeftBorder {
border-left: 0 !important;
}
#fehlercodeInfoCell {
vertical-align: middle;
font-size: 1.2em;
cursor: pointer;
}
+229
View File
@@ -0,0 +1,229 @@
/**
* Copyright (C) 2022 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/>.
*/
//--------------------------------------------------------------------------------------------------------------------
// Configs
// To see debug messages into the browser console set this parameter as true
const CORE_REST_CLIENT_DEBUG = false;
// Default timeout (milliseconds)
const CORE_REST_CLIENT_TIMEOUT = 1000;
//--------------------------------------------------------------------------------------------------------------------
// Constants
// Success
const CORE_REST_CLIENT_SUCCESS = 0;
// Properties present in a response
const CORE_REST_CLIENT_ERROR = "error";
const CORE_REST_CLIENT_RETVAL = "retval";
// HTTP method parameters
const CRC_HTTP_GET_METHOD = "get";
const CRC_HTTP_POST_METHOD = "post";
/**
* Definition and initialization of the object CoreRESTClient
*/
export const CoreRESTClient = {
//------------------------------------------------------------------------------------------------------------------
// Public methods
/**
* Performs a call using the HTTP GET method
* wsParameters is an object
* axiosParameters is an object
*/
get: function(wsURL, wsParameters, axiosParameters = null) {
return CoreRESTClient._axiosCall(wsURL, wsParameters, CRC_HTTP_GET_METHOD, axiosParameters);
},
/**
* Performs a call using the HTTP POST method
* wsParameters is an object
* axiosParameters is an object
*/
post: function(wsURL, wsParameters, axiosParameters = null) {
return CoreRESTClient._axiosCall(wsURL, wsParameters, CRC_HTTP_POST_METHOD, axiosParameters);
},
/**
* Checks if the response is a success
*/
isSuccess: function(response) {
if (typeof response === "object" && response.hasOwnProperty(CORE_REST_CLIENT_ERROR)
&& response.hasOwnProperty(CORE_REST_CLIENT_RETVAL) && response.error == CORE_REST_CLIENT_SUCCESS)
{
return true;
}
return false;
},
/**
* Checks if the response is an error
*/
isError: function(response) {
return !CoreRESTClient.isSuccess(response);
},
/**
* Checks if the response has data
*/
hasData: function(response) {
if (CoreRESTClient.isSuccess(response))
{
if ((typeof response[CORE_REST_CLIENT_RETVAL] === "object" && Object.keys(response[CORE_REST_CLIENT_RETVAL]).length > 0)
|| (typeof response[CORE_REST_CLIENT_RETVAL] === "array" && response[CORE_REST_CLIENT_RETVAL].length > 0)
|| (typeof response[CORE_REST_CLIENT_RETVAL] === "string" && response[CORE_REST_CLIENT_RETVAL].trim() != "")
|| typeof response[CORE_REST_CLIENT_RETVAL] === "number")
{
return true;
}
}
return false;
},
/**
* Retrives data from response object
*/
getData: function(response) {
if (CoreRESTClient.hasData(response))
{
return response[CORE_REST_CLIENT_RETVAL];
}
return null;
},
/**
* Retrives error message from response object
*/
getError: function(response) {
if (typeof response[CORE_REST_CLIENT_RETVAL] === "object"
&& Object.keys(response[CORE_REST_CLIENT_RETVAL]).length > 0
&& response.hasOwnProperty(CORE_REST_CLIENT_RETVAL))
{
return response[CORE_REST_CLIENT_RETVAL];
}
return "Generic error";
},
/**
* Retrives code from response object
*/
getErrorCode: function(response) {
if (typeof response[CORE_REST_CLIENT_RETVAL] === "object" && response.hasOwnProperty(CORE_REST_CLIENT_ERROR))
{
return response[CORE_REST_CLIENT_ERROR];
}
return 1; // Generic error
},
//------------------------------------------------------------------------------------------------------------------
// Private methods
/**
* Generate the router URI using the connection parameters
*/
_generateRouterURI: function(wsURL) {
var uri = null;
// Checks if global JS object FHC_JS_DATA_STORAGE_OBJECT exists
if (typeof FHC_JS_DATA_STORAGE_OBJECT !== "undefined")
{
uri = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + "/" + wsURL;
}
return uri;
},
/**
* Method to print debug info after a controller has been called
*/
_printDebug: function(parameters, response, errorThrown) {
if (CORE_REST_CLIENT_DEBUG === true) // If global const CORE_REST_CLIENT_DEBUG is true, but really true!
{
// Print info about called controller
console.log("Called controller: " + parameters.remoteController);
console.log("Call parameters:"); // parameters given to this call
console.log(parameters);
if (response != null) // if there is a response...
{
console.log("Controller Response:");
console.log(response); // ...print it
}
if (errorThrown != null) // if there is a jQuery error...
{
console.log("jQuery error:");
console.log(errorThrown); // ...print it
}
console.log("--------------------------------------------------------------------------------------------");
}
},
/**
* Performs a call to the server were the CI PHP layer is running
* - wsURL: alias of the core controller to call
* - wsParameters: parameters to give to the called controller
* - type: POST or GET HTTP method
* - axiosParameters: an object to configure the axios call
*/
_axiosCall: function(wsURL, wsParameters, type, axiosParameters) {
// Axios config object
let axiosCallObj = {
method: type,
url: CoreRESTClient._generateRouterURI(wsURL),
timeout: CORE_REST_CLIENT_TIMEOUT // default time out
};
// The ajax call is HTTP GET
if (type == CRC_HTTP_GET_METHOD)
{
axiosCallObj.params = wsParameters;
}
// The ajax call is HTTP POST
else
{
axiosCallObj.data = wsParameters;
}
// Check if axiosParameters is an object
if (typeof axiosParameters === "object")
{
// And then copies the its properties into axiosCallObj
for (var prop in axiosParameters) axiosCallObj[prop] = axiosParameters[prop];
}
// Perform the ajax call via axios
return axios(axiosCallObj);
}
};
+44
View File
@@ -0,0 +1,44 @@
/**
* Copyright (C) 2022 fhcomplete.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {LogsViewerTabulatorOptions} from './TabulatorSetup.js';
import {LogsViewerTabulatorEventHandlers} from './TabulatorSetup.js';
import {CoreFilterCmpt} from '../../components/filter/Filter.js';
import {CoreNavigationCmpt} from '../../components/navigation/Navigation.js';
const logsViewerApp = Vue.createApp({
data: function() {
return {
appSideMenuEntries: {},
logsViewerTabulatorOptions: LogsViewerTabulatorOptions,
logsViewerTabulatorEventHandlers: LogsViewerTabulatorEventHandlers
};
},
components: {
CoreNavigationCmpt,
CoreFilterCmpt
},
methods: {
newSideMenuEntryHandler: function(payload) {
this.appSideMenuEntries = payload;
}
}
});
logsViewerApp.mount('#main');
@@ -0,0 +1,66 @@
/**
* Copyright (C) 2022 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 const LogsViewerTabulatorOptions = {
height: 700,
layout: 'fitColumns',
columns: [
{title: 'Log ID', field: 'LogId', headerFilter: true},
{title: 'Request ID', field: 'RequestId', headerFilter: true},
{title: 'Execution time', field: 'ExecutionTime', headerFilter: true},
{title: 'Executed by', field: 'ExecutedBy', headerFilter: true},
{title: 'Description', field: 'Description', headerFilter: true},
{title: 'Data', field: 'Data', headerFilter: true},
{title: 'Web service type', field: 'WebserviceType', headerFilter: true}
],
rowFormatter: function(row) {
let data = row.getData(); // get data for this row
// If data is not null and provides the property RequestId and it is not null
if (data != null && data.hasOwnProperty('RequestId') && data.RequestId != null)
{
let requestId = data.RequestId;
if (requestId.includes("error"))
{
row.getElement().style.color = "red";
}
else if (requestId.includes("warning"))
{
row.getElement().style.color = "orange";
}
}
}
};
/**
*
*/
export const LogsViewerTabulatorEventHandlers = [
{
event: "rowClick",
handler: function(e, row) {
alert(row.getData().Data);
}
}
];
+195
View File
@@ -0,0 +1,195 @@
import {CoreFilterCmpt} from '../components/Filter.js';
import {CoreNavigationCmpt} from '../components/Navigation.js';
import verticalsplit from "../components/verticalsplit/verticalsplit.js";
import searchbar from "../components/searchbar/searchbar.js";
import fhcapifactory from "./api/fhcapifactory.js";
Vue.$fhcapi = fhcapifactory;
Vue.createApp({
"data": function() {
return {
"title": "Test Search",
"appSideMenuEntries": {},
"searchbaroptions": {
"types": [
"person",
"raum",
"mitarbeiter",
"student",
"prestudent",
"document",
"cms",
"organisationunit"
],
"actions": {
"person": {
"defaultaction": {
"type": "link",
"action": function(data) {
//alert('person defaultaction ' + JSON.stringify(data));
//window.location.href = data.profil;
return data.profil;
}
},
"childactions": [
{
"label": "testchildaction1",
"icon": "fas fa-check-circle",
"type": "function",
"action": function(data) {
alert('person testchildaction 01 ' + JSON.stringify(data));
}
},
{
"label": "testchildaction2",
"icon": "fas fa-file-csv",
"type": "function",
"action": function(data) {
alert('person testchildaction 02 ' + JSON.stringify(data));
}
}
]
},
"raum": {
"defaultaction": {
"type": "function",
"action": function(data) {
alert('raum defaultaction ' + JSON.stringify(data));
}
},
"childactions": [
{
"label": "Rauminformation",
"icon": "fas fa-info-circle",
"type": "link",
"action": function(data) {
return data.infolink;
}
},
{
"label": "Raumreservierung",
"icon": "fas fa-bookmark",
"type": "link",
"action": function(data) {
return data.booklink;
}
}
]
},
"employee": {
"defaultaction": {
"type": "function",
"action": function(data) {
alert('employee defaultaction ' + JSON.stringify(data));
}
},
"childactions": [
{
"label": "testchildaction1",
"icon": "fas fa-address-book",
"type": "function",
"action": function(data) {
alert('employee testchildaction 01 ' + JSON.stringify(data));
}
},
{
"label": "testchildaction2",
"icon": "fas fa-user-slash",
"type": "function",
"action": function(data) {
alert('employee testchildaction 02 ' + JSON.stringify(data));
}
},
{
"label": "testchildaction3",
"icon": "fas fa-bell",
"type": "function",
"action": function(data) {
alert('employee testchildaction 03 ' + JSON.stringify(data));
}
},
{
"label": "testchildaction4",
"icon": "fas fa-calculator",
"type": "function",
"action": function(data) {
alert('employee testchildaction 04 ' + JSON.stringify(data));
}
}
]
},
"organisationunit": {
"defaultaction": {
"type": "function",
"action": function(data) {
alert('organisationunit defaultaction ' + JSON.stringify(data));
}
},
"childactions": []
}
}
},
"searchbaroptions2": {
"types": [
"raum",
"organisationunit"
],
"actions": {
"raum": {
"defaultaction": {
"type": "function",
"action": function(data) {
alert('raum defaultaction ' + JSON.stringify(data));
}
},
"childactions": [
{
"label": "Rauminformation",
"icon": "fas fa-info-circle",
"type": "link",
"action": function(data) {
return data.infolink;
}
},
{
"label": "Raumreservierung",
"icon": "fas fa-bookmark",
"type": "link",
"action": function(data) {
return data.booklink;
}
}
]
},
"organisationunit": {
"defaultaction": {
"type": "function",
"action": function(data) {
alert('organisationunit defaultaction ' + JSON.stringify(data));
}
},
"childactions": []
}
}
}
};
},
"components": {
"CoreNavigationCmpt": CoreNavigationCmpt,
"CoreFilterCmpt": CoreFilterCmpt,
"verticalsplit": verticalsplit,
"searchbar": searchbar
},
"methods": {
"newSideMenuEntryHandler": function(payload) {
this.appSideMenuEntries = payload;
},
"searchfunction": function(searchsettings) {
return Vue.$fhcapi.Search.search(searchsettings);
},
"searchfunctiondummy": function(searchsettings) {
return Vue.$fhcapi.Search.searchdummy(searchsettings);
}
}
}).mount('#main');
+5
View File
@@ -0,0 +1,5 @@
import Search from "./search.js";
export default {
"Search": Search
};
+12
View File
@@ -0,0 +1,12 @@
export default {
search: function(searchsettings) {
const url = FHC_JS_DATA_STORAGE_OBJECT.app_root
+ 'index.ci.php/components/SearchBar/search';
return axios.post(url, searchsettings);
},
searchdummy: function(searchsettings) {
const url = FHC_JS_DATA_STORAGE_OBJECT.app_root
+ 'public/js/apps/api/dummyapi.php/Search';
return axios.post(url, searchsettings);
}
};
+3 -1
View File
@@ -12,5 +12,7 @@ var Bootstrapper = {
$("input[type=text], select, textarea").addClass("form-control");
$("button, input[type=button]").addClass("btn btn-default");
$("table").addClass("table-condensed");
$("#tableDataset").addClass('table-bordered');
}
};
};
+118
View File
@@ -0,0 +1,118 @@
/**
* Copyright (C) 2022 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 const CoreFetchCmpt = {
emits: ['dataFetched'], // this component can emit the event dataFetched that it is catched by this component itself
props: {
refresh: { // to refresh this component
type: Boolean
},
apiFunction: { // the function to call, must return a Promise
required: true,
type: Function
},
apiFunctionParameters: {} // parameters for the apiFunction, type mixed, optional
},
watch: {
/**
* If the refresh property is changed then call fetchData
*/
refresh: function (newValue, oldValue) {
this.fetchData();
}
},
data: function() {
return {
loading: false, // if in loading or not
error: false, // if an error occurred while loading data
errorMessage: null // the error message
};
},
created: function() {
this.fetchData();
},
methods: {
/**
*
*/
fetchData: function() {
this.loading = true; // loader started
// Checks if the apifunction is a callable function
if (typeof this.apiFunction == "function")
{
// Call the function stored in apiFunction
let apiFunctionResult = this.apiFunction(this.apiFunctionParameters);
// It is expected that the function returns a Promise
if (apiFunctionResult instanceof Promise)
{
apiFunctionResult
.then(this.successHandler) // on success
.catch(this.errorHandler) // on error
.finally(this.finallyHandler); // finally in any case
}
else // otherwise display an error
{
this.setError("The called apiFunction does not return a Promise");
}
}
else // otherwise display an error
{
this.setError("Property apiFunction is not a function");
}
},
/**
*
*/
setError: function(errorMessage) {
this.loading = false; // loading ended
this.error = true; // error occurred
this.errorMessage = errorMessage; // save the error message
},
/**
*
*/
successHandler: function(response) {
this.$emit('dataFetched', response.data); // trigger the event dataFetched
},
/**
*
*/
errorHandler: function(error) {
this.setError(error.message);
},
/**
*
*/
finallyHandler: function() {
this.loading = false; // loading ended
}
},
template: `
<slot v-if="loading">
<div class="fetch-loader">Loading...</div>
</slot>
<slot v-if="error">
<div class="fetch-error">{{ errorMessage }}</div>
</slot>
`
};
+139
View File
@@ -0,0 +1,139 @@
/**
* Copyright (C) 2022 fhcomplete.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {CoreRESTClient} from '../../RESTClient.js';
//
const CORE_FILTER_CMPT_TIMEOUT = 7000;
/**
*
*/
export const CoreFilterAPIs = {
/**
*
*/
saveCustomFilter: function(wsParams) {
return CoreRESTClient.post(
'components/Filter/saveCustomFilter',
{
filterUniqueId: wsParams.filterUniqueId,
filterType: wsParams.filterType,
customFilterName: wsParams.customFilterName
},
{
timeout: CORE_FILTER_CMPT_TIMEOUT
}
);
},
/**
*
*/
removeCustomFilter: function(wsParams) {
return CoreRESTClient.post(
'components/Filter/removeCustomFilter',
{
filterUniqueId: wsParams.filterUniqueId,
filterType: wsParams.filterType,
filterId: wsParams.filterId
},
{
timeout: CORE_FILTER_CMPT_TIMEOUT
}
);
},
/**
*
*/
applyFilterFields: function(wsParams) {
return CoreRESTClient.post(
'components/Filter/applyFilterFields',
{
filterUniqueId: wsParams.filterUniqueId,
filterType: wsParams.filterType,
filterFields: wsParams.filterFields
},
{
timeout: CORE_FILTER_CMPT_TIMEOUT
}
);
},
/**
*
*/
addFilterField: function(wsParams) {
return CoreRESTClient.post(
'components/Filter/addFilterField',
{
filterUniqueId: wsParams.filterUniqueId,
filterType: wsParams.filterType,
filterField: wsParams.filterField
},
{
timeout: CORE_FILTER_CMPT_TIMEOUT
}
);
},
/**
*
*/
removeFilterField: function(wsParams) {
return CoreRESTClient.post(
'components/Filter/removeFilterField',
{
filterUniqueId: wsParams.filterUniqueId,
filterType: wsParams.filterType,
filterField: wsParams.filterField
},
{
timeout: CORE_FILTER_CMPT_TIMEOUT
}
);
},
/**
*
*/
getFilterById: function(wsParams) {
return CoreRESTClient.get(
'components/Filter/getFilter',
{
filterUniqueId: wsParams.filterUniqueId,
filterType: wsParams.filterType,
filterId: wsParams.filterId
},
{
timeout: CORE_FILTER_CMPT_TIMEOUT
}
);
},
/**
*
*/
getFilter: function(wsParams) {
return CoreRESTClient.get(
'components/Filter/getFilter',
{
filterUniqueId: wsParams.filterUniqueId,
filterType: wsParams.filterType
},
{
timeout: CORE_FILTER_CMPT_TIMEOUT
}
);
}
};
+724
View File
@@ -0,0 +1,724 @@
/**
* Copyright (C) 2022 fhcomplete.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {CoreFilterAPIs} from './API.js';
import {CoreRESTClient} from '../../RESTClient.js';
import {CoreFetchCmpt} from '../../components/Fetch.js';
//
const FILTER_COMPONENT_NEW_FILTER = 'Filter Component New Filter';
const FILTER_COMPONENT_NEW_FILTER_TYPE = 'Filter Component New Filter Type';
/**
*
*/
export const CoreFilterCmpt = {
emits: ['nwNewEntry'],
components: {
CoreFetchCmpt
},
props: {
title: String,
sideMenu: {
type: Boolean,
default: true
},
filterType: {
type: String,
required: true
},
tabulatorOptions: Object,
tabulatorEvents: Array
},
data: function() {
return {
// FilterCmpt properties
filterName: null,
fields: null,
dataset: null,
datasetMetadata: null,
selectedFields: null,
notSelectedFields: null,
filterFields: null,
columnsAlias: null,
availableFilters: null,
// FetchCmpt binded properties
fetchCmptRefresh: false,
fetchCmptApiFunction: null,
fetchCmptApiFunctionParams: null,
fetchCmptDataFetched: null,
tabulator: null
};
},
created: function() {
this.getFilter(); // get the filter data
},
updated: function() {
//
let dataset = JSON.parse(JSON.stringify(this.dataset));
let fields = JSON.parse(JSON.stringify(this.fields));
let selectedFields = JSON.parse(JSON.stringify(this.selectedFields));
//
let columns = null;
// If the tabulator options has been provided and it contains the property columns
if (this.tabulatorOptions != null && this.tabulatorOptions.hasOwnProperty('columns'))
{
columns = this.tabulatorOptions.columns;
}
// If columns is not an array or it is an array with less elements then the array fields
if (!Array.isArray(columns) || (Array.isArray(columns) && columns.length < fields.length))
{
columns = []; // set it as an empty array
// Loop throught all the retrieved columns from database
for (let i = 0; i < fields.length; i++)
{
// Create a new column having the title equal to the field name
let column = {
title: fields[i],
field: fields[i]
};
// If the column has to be displayed or not
selectedFields.indexOf(fields[i]) >= 0 ? column.visible = true : column.visible = false;
// Add the new column to the list of columns
columns.push(column);
}
}
else // the property columns has been provided in the tabulator options
{
// Loop throught the property columns of the tabulator options
for (let i = 0; i < columns.length; i++)
{
// If the column has to be displayed or not
selectedFields.indexOf(columns[i].field) >= 0 ? columns[i].visible = true : columns[i].visible = false;
if (columns[i].hasOwnProperty('resizable'))
{
columns[i].visible ? columns[i].resizable = true : columns[i].resizable = false;
}
}
}
this.columnsAlias = columns;
// Define a default tabulator options in case it was not provided
let tabulatorOptions = {
height: 500,
layout: "fitColumns",
movableColumns: true,
reactiveData: true,
columns: columns,
data: JSON.parse(JSON.stringify(this.dataset))
};
// If it was provided
if (this.tabulatorOptions != null)
{
// Then copy it...
tabulatorOptions = this.tabulatorOptions;
// ...and overwrite the properties data, reactiveData, movableColumns and columns
tabulatorOptions.data = JSON.parse(JSON.stringify(this.dataset));
tabulatorOptions.columns = columns;
tabulatorOptions.reactiveData = true;
tabulatorOptions.movableColumns = true;
}
// Start the tabulator with the buid options
this.tabulator = new Tabulator(
"#filterTableDataset",
tabulatorOptions
);
// If event handlers have been provided
if (Array.isArray(this.tabulatorEvents) && this.tabulatorEvents.length > 0)
{
// Attach all the provided event handlers to the started tabulator
for (let i = 0; i < this.tabulatorEvents.length; i++)
{
this.tabulator.on(this.tabulatorEvents[i].event, this.tabulatorEvents[i].handler);
}
}
},
methods: {
/**
*
*/
getFilter: function() {
//
this.startFetchCmpt(CoreFilterAPIs.getFilter, null, this.render);
},
/**
*
*/
render: function(response) {
if (CoreRESTClient.hasData(response))
{
let data = CoreRESTClient.getData(response);
this.filterName = data.filterName;
this.dataset = data.dataset;
this.datasetMetadata = data.datasetMetadata;
this.fields = data.fields;
this.selectedFields = data.selectedFields;
this.notSelectedFields = this.fields.filter(x => this.selectedFields.indexOf(x) === -1);
this.filterFields = [];
for (let i = 0; i < data.datasetMetadata.length; i++)
{
for (let j = 0; j < data.filters.length; j++)
{
if (data.datasetMetadata[i].name == data.filters[j].name)
{
let filter = data.filters[j];
filter.type = data.datasetMetadata[i].type;
this.filterFields.push(filter);
break;
}
}
}
// If the side menu is active
if (this.sideMenu === true)
{
this.setSideMenu(data);
}
else // otherwise use the dropdown in the filter options
{
this.setDropDownMenu(data);
}
}
else
{
console.error(CoreRESTClient.getError(response));
}
},
/**
* Set the menu
*/
setSideMenu: function(data) {
let filters = data.sideMenu.filters;
let personalFilters = data.sideMenu.personalFilters;
let filtersArray = [];
for (let filtersCount = 0; filtersCount < filters.length; filtersCount++)
{
let link = filters[filtersCount].link;
if (link == null) link = '#';
filtersArray[filtersArray.length] = {
link: link + filters[filtersCount].filter_id,
description: filters[filtersCount].desc,
sort: filtersCount,
onClickCall: this.handlerGetFilterById
};
}
for (let filtersCount = 0; filtersCount < personalFilters.length; filtersCount++)
{
let link = personalFilters[filtersCount].link;
if (link == null) link = '#';
filtersArray[filtersArray.length] = {
link: link + personalFilters[filtersCount].filter_id,
description: personalFilters[filtersCount].desc,
subscriptDescription: personalFilters[filtersCount].subscriptDescription,
subscriptLinkClass: personalFilters[filtersCount].subscriptLinkClass,
subscriptLinkValue: personalFilters[filtersCount].subscriptLinkValue,
sort: filtersCount,
onClickCall: this.handlerGetFilterById,
onClickSubscriptCall: this.handlerRemoveCustomFilter
};
}
this.availableFilters = filtersArray;
this.$emit(
'nwNewEntry',
{
link: "#",
description: "Filters",
icon: "filter",
children: filtersArray
}
);
},
/**
* Set the drop down menu
*/
setDropDownMenu: function(data) {
let filters = data.sideMenu.filters;
let personalFilters = data.sideMenu.personalFilters;
let filtersArray = [];
for (let filtersCount = 0; filtersCount < filters.length; filtersCount++)
{
let link = filters[filtersCount].link;
if (link == null) link = '#';
filtersArray[filtersArray.length] = {
option: filters[filtersCount].filter_id,
description: filters[filtersCount].desc
};
}
for (let filtersCount = 0; filtersCount < personalFilters.length; filtersCount++)
{
let link = personalFilters[filtersCount].link;
if (link == null) link = '#';
filtersArray[filtersArray.length] = {
option: personalFilters[filtersCount].filter_id,
description: personalFilters[filtersCount].desc
};
}
this.availableFilters = filtersArray;
},
/**
* Used to start/refresh the FetchCmpt
*/
startFetchCmpt: function(apiFunction, apiFunctionParameters, dataFetchedCallback) {
// Assign the function api of the FetchCmpt binded property
this.fetchCmptApiFunction = apiFunction;
// In case a null value is provided set the parameters as an empty object
if (apiFunctionParameters == null) apiFunctionParameters = {};
// Always needed parameters
apiFunctionParameters.filterUniqueId = FHC_JS_DATA_STORAGE_OBJECT.called_path + "/" + FHC_JS_DATA_STORAGE_OBJECT.called_method;
apiFunctionParameters.filterType = this.filterType;
// Assign parameters to the FetchCmpt binded properties
this.fetchCmptApiFunctionParams = apiFunctionParameters;
// Assign data fetch callback to the FetchCmpt binded properties
this.fetchCmptDataFetched = dataFetchedCallback;
// Set the FetchCmpt binded property refresh to have the component to refresh
// NOTE: this should be the last one to be called because it triggers the FetchCmpt to start to refresh
this.fetchCmptRefresh === true ? this.fetchCmptRefresh = false : this.fetchCmptRefresh = true;
},
// ------------------------------------------------------------------------------------------------------------------
// Event handlers
/**
*
*/
handlerSaveCustomFilter: function(event) {
//
this.startFetchCmpt(
CoreFilterAPIs.saveCustomFilter,
{
customFilterName: document.getElementById('customFilterName').value
},
this.getFilter
);
},
/**
*
*/
handlerRemoveCustomFilter: function(event) {
//
this.startFetchCmpt(
CoreFilterAPIs.removeCustomFilter,
{
filterId: event.currentTarget.getAttribute("href").substring(1)
},
this.getFilter
);
},
/**
*
*/
handlerApplyFilterFields: function(event) {
let filterFields = [];
let filterFieldDivRows = document.getElementById('filterFields').getElementsByClassName('row');
for (let i = 0; i< filterFieldDivRows.length; i++)
{
let filterField = {};
for (let j = 0; j< filterFieldDivRows[i].children.length; j++)
{
let filterColumn = filterFieldDivRows[i].children[j];
let filterColumnElement = filterColumn.children[0];
// If the first column then search for the fields dropdown
if (j == 0) filterColumnElement = filterColumnElement.querySelector('select[name=fieldName]');
// If the filter name is _not_ null and it is _not_ a new filter
if (filterColumnElement.name != null && filterColumnElement.name != FILTER_COMPONENT_NEW_FILTER)
{
// Condition
if (filterColumnElement.name == 'condition' && filterColumnElement.value == "")
{
alert("Please fill all the filter options");
return;
}
// Name
if (filterColumnElement.name == 'fieldName')
{
filterField.name = filterColumnElement.value;
}
// Operation
if (filterColumnElement.name == 'operation')
{
filterField.operation = filterColumnElement.value;
}
// Condition
if (filterColumnElement.name == 'condition')
{
filterField.condition = filterColumnElement.value;
}
// Option
if (filterColumnElement.name == 'option')
{
filterField.option = filterColumnElement.value;
}
}
}
if (Object.entries(filterField).length > 0) filterFields.push(filterField);
}
//
this.startFetchCmpt(
CoreFilterAPIs.applyFilterFields,
{
filterFields: filterFields
},
this.getFilter
);
},
/**
*
*/
handlerChangeFilterField: function(oldValue, newValue) {
// If an old filter has been changed
if (oldValue != "")
{
for (let i = 0; i < this.filterFields.length; i++)
{
if (this.filterFields[i].name == oldValue)
{
this.filterFields.splice(i, 1);
break;
}
}
}
// Then add the new filter
for (let i = 0; i < this.datasetMetadata.length; i++)
{
if (this.datasetMetadata[i].name == newValue)
{
let filter = {
name: this.datasetMetadata[i].name,
type: this.datasetMetadata[i].type
};
this.filterFields.push(filter);
break;
}
}
},
/**
*
*/
handlerAddNewFilter: function(event) {
// Adds a new empty filter
this.filterFields.push({
name: FILTER_COMPONENT_NEW_FILTER,
type: FILTER_COMPONENT_NEW_FILTER_TYPE
});
},
/*
*
*/
handlerToggleSelectedField: function(event) {
// If it is a selected field
if (this.selectedFields.indexOf(event.target.innerText) != -1)
{
// then hide it
this.tabulator.hideColumn(event.target.innerText);
// and remove it from the this.selectedFields property
this.selectedFields.splice(this.selectedFields.indexOf(event.target.innerText), 1);
}
else // otherwise
{
// show it
this.tabulator.showColumn(event.target.innerText);
// and add it to the this.selectedFields property
this.selectedFields.push(event.target.innerText);
}
},
/**
*
*/
handlerRemoveFilterField: function(event) {
//
this.startFetchCmpt(
CoreFilterAPIs.removeFilterField,
{
filterField: event.currentTarget.getAttribute('field-to-remove')
},
this.getFilter
);
},
/**
*
*/
handlerGetFilterById: function(event) {
let filterId = null;
// Get the attribute href if side menu is rendered
let attr = event.currentTarget.getAttribute("href");
// Otherwise get the value of the drop down menu
if (attr == null)
{
filterId = event.currentTarget.value;
}
else
{
filterId = attr.substring(1);
}
// Ajax call
this.startFetchCmpt(
CoreFilterAPIs.getFilterById,
{
filterId: filterId
},
this.render
);
}
},
template: `
<!-- Load filter data -->
<core-fetch-cmpt
v-bind:api-function="fetchCmptApiFunction"
v-bind:api-function-parameters="fetchCmptApiFunctionParams"
v-bind:refresh="fetchCmptRefresh"
@data-fetched="fetchCmptDataFetched">
</core-fetch-cmpt>
<div class="row" v-if="title != null && title != ''">
<div class="col-lg-12">
<h3 class="page-header">
{{ title }}
</h3>
</div>
</div>
<div id="filterCollapsables">
<div class="filter-header-title">
<span class="filter-header-title-span-filter">[ {{ filterName }} ]</span>
<span data-bs-toggle="collapse" data-bs-target="#collapseFilters" class="filter-header-title-span-icon fa-solid fa-filter fa-xl"></span>
<span data-bs-toggle="collapse" data-bs-target="#collapseColumns" class="filter-header-title-span-icon fa-solid fa-table-columns fa-xl"></span>
</div>
<div id="collapseColumns" class="card-body collapse" data-bs-parent="#filterCollapsables">
<div class="card">
<!-- Filter fields options -->
<div class="row card-body filter-options-div">
<div class="filter-fields-area">
<template v-for="fieldToDisplay in fields">
<div
class="filter-fields-field"
v-bind:class="selectedFields.indexOf(fieldToDisplay) != -1 ? 'text-light bg-dark' : '' "
@click=handlerToggleSelectedField
>
{{ fieldToDisplay }}
</div>
</template>
</div>
</div>
</div>
</div>
<div id="collapseFilters" class="card-body collapse" data-bs-parent="#filterCollapsables">
<div class="card">
<!-- Filter options -->
<div class="card-body" v-if="!sideMenu">
<select
class="form-select"
@change="handlerGetFilterById"
>
<option value="">Bitte auswählen...</option>
<template v-for="availableFilter in availableFilters">
<option v-bind:value="availableFilter.option">{{ availableFilter.description }}</option>
</template>
</select>
</div>
<div class="card-body filter-options-div">
<div>
<span>
Neuer Filter
</span>
<span>
<button class="btn btn-outline-dark" type="button" @click=handlerAddNewFilter>+</button>
</span>
</div>
<div id="filterFields" class="filter-filter-fields">
<template v-for="(filterField, index) in filterFields">
<div class="row">
<div class="col-5">
<div class="input-group">
<span class="input-group-text">Filter {{ index + 1 }}</span>
<select
class="form-select"
name="fieldName"
v-bind:value="filterField.name"
@change="handlerChangeFilterField(filterField.name, $event.target.value)"
>
<option value="">Feld zum Filter hinzufügen...</option>
<template v-for="columnAlias in columnsAlias">
<option v-bind:value="columnAlias.field">{{ columnAlias.title }}</option>
</template>
</select>
</div>
</div>
<!-- Numeric -->
<template
v-if="filterField.type.toLowerCase().indexOf('int') >= 0">
<div class="col-2">
<select class="form-select" name="operation" v-model="filterField.operation">
<option value="equal">Gleich</option>
<option value="nequal">Nicht gleich</option>
<option value="gt">Größer als</option>
<option value="lt">Weniger als</option>
</select>
</div>
<div class="col-3">
<input type="number" class="form-control" v-bind:value="filterField.condition" name="condition">
</div>
<div class="col">
<button
class="btn btn-outline-dark"
type="button"
v-bind:field-to-remove="filterField.name"
@click=handlerRemoveFilterField>
&emsp;X&emsp;
</button>
</div>
</template>
<!-- Text -->
<template
v-if="filterField.type.toLowerCase().indexOf('varchar') >= 0
|| filterField.type.toLowerCase().indexOf('text') >= 0
|| filterField.type.toLowerCase().indexOf('bpchar') >= 0">
<div class="col-2">
<select class="form-select" name="operation" v-model="filterField.operation">
<option value="equal">Gleich</option>
<option value="nequal">Nicht gleich</option>
<option value="contains">Enthält</option>
<option value="ncontains">Enthält nicht</option>
</select>
</div>
<div class="col-3">
<input type="text" class="form-control" v-bind:value="filterField.condition" name="condition">
</div>
<div class="col">
<button
class="btn btn-outline-dark"
type="button"
v-bind:field-to-remove="filterField.name"
@click=handlerRemoveFilterField>
&emsp;X&emsp;
</button>
</div>
</template>
<!-- Timestamp and date -->
<template
v-if="filterField.type.toLowerCase().indexOf('timestamp') >= 0
|| filterField.type.toLowerCase().indexOf('date') >= 0">
<div class="col-2">
<select class="form-select" name="operation" v-model="filterField.operation">
<option value="gt">Größer als</option>
<option value="lt">Weniger als</option>
<option value="set">Eingestellt ist</option>
<option value="nset">Eingestellt nicht ist</option>
</select>
</div>
<div class="col-1">
<input type="number" class="form-control" v-bind:value="filterField.condition" name="condition">
</div>
<div class="col-2">
<select class="form-select" name="option" v-model="filterField.option">
<option value="minutes">Minuten</option>
<option value="hours">Stunden</option>
<option value="days">Tage</option>
<option value="months">Monate</option>
</select>
</div>
<div class="col">
<button
class="btn btn-outline-dark"
type="button"
v-bind:field-to-remove="filterField.name"
@click=handlerRemoveFilterField
> - </button>
</div>
</template>
</div>
</template>
</div>
<!-- Filter save options -->
<div class="row">
<div class="col-7">
<div class="input-group">
<input type="text" class="form-control" placeholder="Filternamen eingeben..." id="customFilterName">
<button type="button" class="btn btn-outline-secondary" @click=handlerSaveCustomFilter>Filter speichern</button>
</div>
</div>
<div class="col">
<button type="button" class="btn btn-outline-dark" @click=handlerApplyFilterFields>Filter anwenden</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Tabulator -->
<div id="filterTableDataset" class="filter-table-dataset"></div>
`
};
+56
View File
@@ -0,0 +1,56 @@
/**
* Copyright (C) 2022 fhcomplete.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {CoreRESTClient} from '../../RESTClient.js';
//
const CORE_NAVIGATION_CMPT_TIMEOUT = 2000;
/**
*
*/
export const CoreNavigationAPIs = {
/**
*
*/
getHeader: function(navigationPage) {
return CoreRESTClient.get(
'system/Navigation/header',
{
navigation_page: navigationPage
},
{
timeout: CORE_NAVIGATION_CMPT_TIMEOUT
}
);
},
/**
*
*/
getMenu: function(navigationPage) {
return CoreRESTClient.get(
'system/Navigation/menu',
{
navigation_page: navigationPage
},
{
timeout: CORE_NAVIGATION_CMPT_TIMEOUT
}
);
}
};
@@ -0,0 +1,173 @@
/**
* Copyright (C) 2022 fhcomplete.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {CoreNavigationAPIs} from './API.js';
import {CoreRESTClient} from '../../RESTClient.js';
import {CoreFetchCmpt} from '../../components/Fetch.js';
/**
*
*/
export const CoreNavigationCmpt = {
components: {
CoreFetchCmpt
},
props: {
addHeaderMenuEntries: Object, // property used to add new header menu entries from another app/component
addSideMenuEntries: Object, // property used to add new side menu entries from another app/component
hideTopMenu: Boolean,
leftNavCssClasses: {
type: String,
default: 'navbar navbar-left-side'
}
},
data: function() {
return {
headerMenu: {}, // header menu entries
sideMenu: {} // side menu entries
};
},
computed: {
/**
*
*/
headerMenuEntries: function() {
//
if (this.headerMenu != null && this.addHeaderMenuEntries != null && Object.keys(this.addHeaderMenuEntries).length > 0)
{
this.headerMenu[this.addHeaderMenuEntries.description] = this.addHeaderMenuEntries;
}
return this.headerMenu;
},
/**
*
*/
sideMenuEntries: function() {
//
if (this.sideMenu != null && this.addSideMenuEntries != null && Object.keys(this.addSideMenuEntries).length > 0)
{
this.sideMenu[this.addSideMenuEntries.description] = this.addSideMenuEntries;
}
return this.sideMenu;
}
},
methods: {
/**
*
*/
getNavigationPage: function() {
return FHC_JS_DATA_STORAGE_OBJECT.called_path + "/" + FHC_JS_DATA_STORAGE_OBJECT.called_method;
},
/**
*
*/
fetchCmptApiFunctionHeader: function() {
return CoreNavigationAPIs.getHeader(this.getNavigationPage());
},
/**
*
*/
fetchCmptApiFunctionSideMenu: function() {
return CoreNavigationAPIs.getMenu(this.getNavigationPage());
},
/**
*
*/
fetchCmptDataFetchedHeader: function(data) {
if (CoreRESTClient.hasData(data)) this.headerMenu = CoreRESTClient.getData(data);
},
/**
*
*/
fetchCmptDataFetchedMenu: function(data) {
if (CoreRESTClient.hasData(data)) this.sideMenu = CoreRESTClient.getData(data);
},
/**
*
*/
getDataBsToggle: function(header) {
return !header.children ? null : 'dropdown';
}
},
template: `
<!-- Load head menu -->
<core-fetch-cmpt v-bind:api-function="fetchCmptApiFunctionHeader" @data-fetched="fetchCmptDataFetchedHeader"></core-fetch-cmpt>
<!-- Load side menu -->
<core-fetch-cmpt v-bind:api-function="fetchCmptApiFunctionSideMenu" @data-fetched="fetchCmptDataFetchedMenu"></core-fetch-cmpt>
<!-- Top menu -->
<nav class="navbar navbar-expand-lg navbar-header" v-if="!hideTopMenu">
<ul class="navbar-nav">
<!-- 1st level -->
<template v-for="header in headerMenuEntries">
<li class="nav-item dropdown">
<a class="nav-link header-menu-link-entry"
v-bind:data-bs-toggle="this.getDataBsToggle(header)"
v-bind:class="{ 'dropdown-toggle': header.children }"
v-bind:href="header.link"
>
<i class="fa-solid fa-fw header-menu-icon" v-bind:class="'fa-' + header.icon" v-if="header.icon"></i> {{ header.description }}
</a>
<ul class="dropdown-menu" v-if="header.children">
<!-- 2nd level -->
<template v-for="child in header.children">
<li><a class="dropdown-item" v-bind:href="child.link">{{ child.description }}</a></li>
</template>
</ul>
</li>
</template>
</ul>
<slot></slot>
</nav>
<!-- Left side menu -->
<nav :class="leftNavCssClasses">
<ul class="navbar-nav">
<!-- 1st level -->
<template v-for="menu in sideMenuEntries">
<li class="nav-item">
<a class="nav-link left-side-menu-link-entry" v-bind:href="menu.link" @click=menu.onClickCall>
<i class="fa fa-fw" v-bind:class="'fa-'+ menu.icon"></i> {{ menu.description }}
</a>
<ul class="nav-link left-side-menu-second-level" v-if="menu.children">
<!-- 2nd level -->
<template v-for="child in menu.children">
<li>
<span>
<a class="nav-link left-side-menu-link-entry" v-bind:href="child.link" @click=child.onClickCall>
&emsp;&emsp;{{ child.description }}
</a>
<a
class="nav-link left-side-menu-link-entry"
v-bind:class="child.subscriptLinkClass"
v-if="child.subscriptDescription"
v-bind:href="child.link"
@click=child.onClickSubscriptCall
>
{{ child.subscriptDescription }}
</a>
</span>
</li>
</template>
</ul>
</li>
</template>
</ul>
</nav>
`
};
+31
View File
@@ -0,0 +1,31 @@
export default {
props: {
res: {
type: Object
},
action: {
type: Object
},
cssclass: {
type: String,
default: ''
}
},
emits: [ 'actionexecuted' ],
template: `
<a :class="this.cssclass" :href="this.getactionhref()"
@click="(this.action.type === 'function') ? this.execaction() : null">
<slot>Action</slot>
</a>
`,
methods: {
getactionhref: function() {
return (this.action.type === 'link') ? this.action.action(this.res)
: 'javascript:void(0);';
},
execaction: function() {
this.action.action(this.res);
this.$emit('actionexecuted');
}
}
};
+28
View File
@@ -0,0 +1,28 @@
import action from "./action.js";
export default {
props: [ "res", "actions" ],
components: {
action: action
},
emits: [ 'actionexecuted' ],
template: `
<ul class="searchbar_actions" v-if="this.actions.length > 0">
<li v-for="(action, index) in this.actions" :key="action.label">
<action :res="this.res" :action="action" :cssclass="'btn btn-primary btn-sm'" @actionexecuted="$emit('actionexecuted')">
<i v-if="this.hasicon(index)" :class="this.geticonclass(index)"></i>
<span class="p-2">{{ action.label }}</span>
</action>
</li>
</ul>
<div class="mb-3" v-else=""></div>
`,
methods: {
hasicon: function(index) {
return (typeof this.actions[index].icon !== "undefined");
},
geticonclass: function(index) {
return this.actions[index].icon;
}
}
};
@@ -0,0 +1,89 @@
import action from "./action.js";
import actions from "./actions.js";
export default {
props: [ "res", "actions" ],
components: {
action: action,
actions: actions
},
emits: [ 'actionexecuted' ],
template: `
<div class="searchbar_result searchbar_employee">
<div class="searchbar_grid">
<div class="searchbar_icon">
<action :res="this.res" :action="this.actions.defaultaction" @actionexecuted="$emit('actionexecuted')">
<img v-if="(typeof res.photo_url !== 'undefined') && (res.photo_url !== null)" :src="res.photo_url"
class="rounded-circle" height="100" />
<i v-else class="fas fa-user-circle fa-5x"></i>
</action>
</div>
<div class="searchbar_data">
<action :res="this.res" :action="this.actions.defaultaction" @actionexecuted="$emit('actionexecuted')">
<span class="fw-bold">{{ res.name }}</span>
</action>
<div class="mb-3"></div>
<div class="searchbar_table">
<div class="searchbar_tablerow">
<div class="searchbar_tablecell">Standard-Kostenstelle</div>
<div class="searchbar_tablecell">
<ul class="searchbar_inline_ul" v-if="res.standardkostenstelle.length > 0">
<li v-for="(stdkst, idx) in res.standardkostenstelle" :key="idx">{{ stdkst }}</li>
</ul>
<span v-else="">keine</span>
</div>
</div>
<div class="searchbar_tablerow">
<div class="searchbar_tablecell">Organisations-Einheit</div>
<div class="searchbar_tablecell">
<ul class="searchbar_inline_ul" v-if="res.organisationunit_name.length > 0">
<li v-for="(oe, idx) in res.organisationunit_name" :key="idx">{{ oe }}</li>
</ul>
<span v-else="">keine</span>
</div>
</div>
<div class="searchbar_tablerow">
<div class="searchbar_tablecell">EMail</div>
<div class="searchbar_tablecell">
<a :href="this.mailtourl">
{{ res.email }}
</a>
</div>
</div>
<div class="searchbar_tablerow">
<div class="searchbar_tablecell">Telefon</div>
<div class="searchbar_tablecell">
<a :href="this.telurl">
{{ res.phone }}
</a>
</div>
</div>
</div>
<actions :res="this.res" :actions="this.actions.childactions" @actionexecuted="$emit('actionexecuted')"></actions>
</div>
</div>
</div>
`,
methods: {
},
computed: {
mailtourl: function() {
return 'mailto:' + this.res.email;
},
telurl: function() {
return 'tel:' + this.res.phone;
}
}
};
@@ -0,0 +1,82 @@
import action from "./action.js";
import actions from "./actions.js";
export default {
props: [ "res", "actions" ],
components: {
action: action,
actions: actions
},
emits: [ 'actionexecuted' ],
template: `
<div class="searchbar_result searchbar_organisationunit">
<div class="searchbar_grid">
<div class="searchbar_icon">
<action :res="this.res" :action="this.actions.defaultaction" @actionexecuted="$emit('actionexecuted')">
<i class="fas fa-sitemap fa-4x"></i>
</action>
</div>
<div class="searchbar_data">
<action :res="this.res" :action="this.actions.defaultaction" @actionexecuted="$emit('actionexecuted')">
<span class="fw-bold">{{ res.name }}</span>
</action>
<div class="mb-3"></div>
<div class="searchbar_table">
<div class="searchbar_tablerow">
<div class="searchbar_tablecell">übergeordnete OrgEinheit</div>
<div class="searchbar_tablecell">
{{ res.parentoe_name }}
</div>
</div>
<div class="searchbar_tablerow">
<div class="searchbar_tablecell">Gruppen-EMail</div>
<div class="searchbar_tablecell">
<a :href="this.mailtourl">
{{ res.mailgroup }}
</a>
</div>
</div>
<div class="searchbar_tablerow">
<div class="searchbar_tablecell">Leiter</div>
<div class="searchbar_tablecell">
<ul class="searchbar_inline_ul" v-if="res.leaders.length > 0">
<li v-for="(leader, idx) in res.leaders" :key="idx">{{ leader.name }}</li>
</ul>
<span v-else="">N.N.</span>
</div>
</div>
<div class="searchbar_tablerow">
<div class="searchbar_tablecell">Mitarbeiter-Anzahl</div>
<div class="searchbar_tablecell">
{{ res.number_of_people }}
</div>
</div>
</div>
<actions :res="this.res" :actions="this.actions.childactions" @actionexecuted="$emit('actionexecuted')"></actions>
</div>
</div>
</div>
`,
methods: {
},
computed: {
mailtourl: function() {
return 'mailto:' + this.res.mailgroup;
},
telurl: function() {
return 'tel:' + this.res.phone;
}
}
};
+55
View File
@@ -0,0 +1,55 @@
import action from "./action.js";
import actions from "./actions.js";
export default {
props: [ "res", "actions" ],
components: {
action: action,
actions: actions
},
emits: [ 'actionexecuted' ],
template: `
<div class="searchbar_result searchbar_person">
<div class="searchbar_grid">
<div class="searchbar_icon">
<action :res="this.res" :action="this.actions.defaultaction" @actionexecuted="$emit('actionexecuted')">
<img v-if="(typeof res.foto !== 'undefined') && (res.foto !== null)" :src="res.foto"
class="rounded-circle" height="100" />
<i v-else class="fas fa-user-circle fa-5x"></i>
</action>
</div>
<div class="searchbar_data">
<action :res="this.res" :action="this.actions.defaultaction" @actionexecuted="$emit('actionexecuted')">
<span class="fw-bold">{{ res.gn }} {{ res.sn }}</span>
</action>
<div class="mb-3"></div>
<div class="searchbar_table">
<div class="searchbar_tablerow">
<div class="searchbar_tablecell">EMail</div>
<div class="searchbar_tablecell">
<a :href="this.mailtourl">
{{ res.mail }}
</a>
</div>
</div>
</div>
<actions :res="this.res" :actions="this.actions.childactions" @actionexecuted="$emit('actionexecuted')"></actions>
</div>
</div>
</div>
`,
methods: {
},
computed: {
mailtourl: function() {
return 'mailto:' + this.res.mail;
}
}
};
+51
View File
@@ -0,0 +1,51 @@
import action from "./action.js";
import actions from "./actions.js";
export default {
props: [ "res", "actions" ],
components: {
action: action,
actions: actions
},
emits: [ 'actionexecuted' ],
template: `
<div class="searchbar_result searchbar_raum">
<div class="searchbar_grid">
<div class="searchbar_icon">
<action :res="this.res" :action="this.actions.defaultaction" @actionexecuted="$emit('actionexecuted')">
<i class="fas fa-door-open fa-4x"></i>
</action>
</div>
<div class="searchbar_data">
<action :res="this.res" :action="this.actions.defaultaction" @actionexecuted="$emit('actionexecuted')">
<span class="fw-bold">{{ res.r }}</span>
</action>
<div class="mb-3"></div>
<div class="searchbar_table">
<div class="searchbar_tablerow">
<div class="searchbar_tablecell">Gebäude</div>
<div class="searchbar_tablecell">{{ res.g }}</div>
</div>
<div class="searchbar_tablerow">
<div class="searchbar_tablecell">Stockwerk</div>
<div class="searchbar_tablecell">{{ res.s }}</div>
</div>
<div class="searchbar_tablerow">
<div class="searchbar_tablecell">Raumnummer</div>
<div class="searchbar_tablecell">{{ res.rn }}</div>
</div>
</div>
<actions :res="this.res" :actions="this.actions.childactions" @actionexecuted="$emit('actionexecuted')"></actions>
</div>
</div>
</div>
`,
methods: {
}
};
+160
View File
@@ -0,0 +1,160 @@
import person from "./person.js";
import raum from "./raum.js";
import employee from "./employee.js";
import organisationunit from "./organisationunit.js";
export default {
props: [ "searchoptions", "searchfunction" ],
data: function() {
return {
searchtimer: null,
hidetimer: null,
showsettings: false,
searchsettings: {
searchstr: '',
types: []
},
showresult: false,
searchresult: [],
searching: false,
error: null
};
},
components: {
person: person,
raum: raum,
employee: employee,
organisationunit: organisationunit
},
template: `
<form ref="searchform" class="d-flex me-3" action="javascript:void(0);"
@focusin="this.searchfocusin" @focusout="this.searchfocusout">
<div class="input-group me-2 bg-white">
<input ref="searchbox" @keyup="this.search" @focus="this.showsearchresult"
v-model="this.searchsettings.searchstr" class="form-control"
type="search" placeholder="Search" aria-label="Search">
<button ref="settingsbutton" @click="this.togglesettings" class="btn btn-outline-secondary" type="button" id="search-filter"><i class="fas fa-cog"></i></button>
</div>
<div v-show="this.showresult" ref="result"
class="searchbar_results" tabindex="-1">
<div v-if="this.searching">
<i class="fas fa-spinner fa-spin fa-2x"></i>
</div>
<div v-else-if="this.error !== null">{{ this.error }}</div>
<div v-else-if="this.searchresult.length < 1">Es wurden keine Ergebnisse gefunden.</div>
<template v-else="" v-for="res in this.searchresult">
<person v-if="res.type === 'person'" :res="res" :actions="this.searchoptions.actions.person" @actionexecuted="this.hideresult"></person>
<employee v-else-if="res.type === 'mitarbeiter'" :res="res" :actions="this.searchoptions.actions.employee" @actionexecuted="this.hideresult"></employee>
<organisationunit v-else-if="res.type === 'organisationunit'" :res="res" :actions="this.searchoptions.actions.organisationunit" @actionexecuted="this.hideresult"></organisationunit>
<raum v-else-if="res.type === 'raum'" :res="res" :actions="this.searchoptions.actions.raum" @actionexecuted="this.hideresult"></raum>
<div v-else="">Unbekannter Ergebnistyp: '{{ res.type }}'.</div>
</template>
</div>
<div v-show="this.showsettings" ref="settings"
class="searchbar_settings" tabindex="-1">
<div class="btn-group" v-if="this.searchoptions.types.length > 0">
<template v-for="(type, index) in this.searchoptions.types" :key="type">
<input type="checkbox" class="btn-check" :id="this.$.uid + 'search_type_' + index" :value="type" v-model="this.searchsettings.types"/>
<label class="btn btn-outline-secondary" :for="this.$.uid + 'search_type_' + index">{{ type }}</label>
</template>
</div>
<div class="mb-2"></div>
<button ref="settingsrefreshsearch" @click="this.refreshsearch" class="btn btn-primary" type="button">Übernehmen</button>
</div>
</form>
`,
beforeMount: function() {
this.updateSearchOptions();
},
methods: {
updateSearchOptions: function() {
this.searchsettings.types = [];
for( const idx in this.searchoptions.types ) {
this.searchsettings.types.push(this.searchoptions.types[idx]);
}
},
calcSearchResultExtent: function() {
var rect = this.$refs.searchbox.getBoundingClientRect();
//console.log(window.innerWidth + ' ' + window.innerHeight + ' ' + JSON.stringify(rect));
this.$refs.result.style.top = Math.floor(rect.bottom + 3) + 'px';
this.$refs.result.style.right = Math.floor(window.innerWidth - rect.right) + 'px';
this.$refs.result.style.width = Math.floor(window.innerWidth * 0.75) + 'px';
this.$refs.result.style.height = Math.floor(window.innerHeight * 0.75) + 'px';
},
search: function() {
if( this.searchtimer !== null ) {
clearTimeout(this.searchtimer);
}
if( this.searchsettings.searchstr.length >= 3 ) {
this.calcSearchResultExtent();
this.searchtimer = setTimeout(
this.callsearchapi,
500
);
} else {
this.showresult = false;
}
},
callsearchapi: function() {
var that = this;
this.error = null;
this.searchresult = [];
this.searching = true;
this.showsearchresult();
this.searchfunction(this.searchsettings)
.then(function(response) {
that.searchresult = response.data.data;
})
.catch(function(error) {
that.error = 'Bei der Suche ist ein Fehler aufgetreten.'
+ ' ' + error.message;
})
.finally(function() {
that.searching = false;
});
},
refreshsearch: function() {
this.search();
this.togglesettings();
},
calcSearchSettingsExtent: function() {
var rect = this.$refs.settingsbutton.getBoundingClientRect();
//console.log(window.innerWidth + ' ' + window.innerHeight + ' ' + JSON.stringify(rect));
this.$refs.settings.style.top = Math.floor(rect.bottom + 3) + 'px';
this.$refs.settings.style.right = Math.floor(window.innerWidth - rect.right) + 'px';
this.$refs.settings.style.width = Math.floor(window.innerWidth * 0.5) + 'px';
//this.$refs.settings.style.height = Math.floor(window.innerHeight * 0.5) + 'px';
},
togglesettings: function() {
this.showsettings = !this.showsettings;
this.calcSearchSettingsExtent();
},
hideresult: function() {
this.showresult = false;
window.removeEventListener('resize', this.calcSearchResultExtent);
},
showsearchresult: function() {
if( this.searchsettings.searchstr.length >= 3 ) {
this.showresult = true;
window.addEventListener('resize', this.calcSearchResultExtent);
}
},
searchfocusin: function(e) {
e.preventDefault();
e.stopPropagation();
if( this.hidetimer !== null ) {
clearTimeout(this.hidetimer);
}
},
searchfocusout: function(e) {
e.preventDefault();
e.stopPropagation();
this.hidetimer = setTimeout(
this.hideresult,
100
);
}
}
};
@@ -0,0 +1,138 @@
export default {
data: function() {
return {
availHeight: 0,
topheight: 0,
bottomheight: 0,
mousePosY: 0,
resize: false,
vsplitter: null,
vsplitterOffset: 0,
selfOffsetTop: 0
};
},
template: `
<div ref="verticalsplit">
<div ref="toppanel" class="verticalsplitted"
:style="{height: this.topheightcss}">
<slot name="top">
<p>Top Panel</p>
</slot>
</div>
<div ref="vsplitter" class="verticalsplitter"
:class="this.topOrBottomClass" @mousedown="this.dragStart">
<div class="splitactions" :class="this.topOrBottomClass">
<span @click="this.collapseTop" class="splitaction">
<i class="fas fa-angle-up"></i>
</span>
<span @dblclick="this.showBoth" class="splitaction resize">
<i class="fas fa-grip-horizontal"></i>
</span>
<span @click="this.collapseBottom" class="splitaction">
<i class="fas fa-angle-down"></i>
</span>
</div>
</div>
<div ref="bottompanel" class="verticalsplitted"
:style="{height: this.bottomheightcss}">
<slot name="bottom">
<p/>
</slot>
</div>
</div>
`,
mounted: function() {
this.calcHeights();
this.trackVerticalSplitterOffsetTop();
window.addEventListener('resize', this.calcHeights);
},
updated: function() {
this.trackVerticalSplitterOffsetTop();
},
methods: {
calcHeights: function() {
var windowheight = window.innerHeight;
var oldavailHeight = this.availHeight;
this.selfOffsetTop = this.$refs.verticalsplit.offsetTop;
this.availHeight = windowheight - this.selfOffsetTop - this.$refs.vsplitter.offsetHeight;
if( (this.topheight === 0 && this.bottomheight === 0) || oldavailHeight === 0 ) {
this.topheight = Math.floor(this.availHeight/2);
} else {
this.topheight = Math.floor( ((((this.topheight * 100) / oldavailHeight) / 100) * this.availHeight) );
}
this.bottomheight = this.availHeight - this.topheight;
},
collapseTop: function() {
this.calcHeights();
this.topheight = 0;
this.bottomheight = this.availHeight;
},
collapseBottom: function() {
this.calcHeights();
this.topheight = this.availHeight;
this.bottomheight = 0;
},
showBoth: function() {
this.topheight = Math.floor(this.availHeight/2);
this.bottomheight = Math.floor(this.availHeight/2);
},
isCollapsed: function() {
if( this.topheight === 0 ) {
return 'top';
} else if ( this.bottomheight === 0 ) {
return 'bottom';
} else {
return false;
}
},
dragStart: function(e) {
e.preventDefault();
e.stopPropagation();
window.addEventListener('mouseup', this.dragEnd);
window.addEventListener('mousemove', this.drag);
this.resize = true;
this.mousePosY = e.clientY;
},
drag: function(e) {
if( !this.resize ) {
return;
}
e.preventDefault();
e.stopPropagation();
var offsetY = e.clientY - this.mousePosY;
this.topheight = this.topheight + offsetY;
if( this.topheight < 0 ) {
this.topheight = 0;
}
if( this.topheight > this.availHeight ) {
this.topheight = this.availHeight;
}
this.bottomheight = this.availHeight - this.topheight;
this.mousePosY = e.clientY;
},
dragEnd: function(e) {
e.preventDefault();
e.stopPropagation();
window.removeEventListener('mousemove', this.drag);
window.removeEventListener('mouseup', this.dragEnd);
this.resize = false;
this.mousePosY = e.clientY;
},
trackVerticalSplitterOffsetTop: function() {
this.vsplitterOffset = this.$refs.vsplitter.offsetTop;
}
},
computed: {
topOrBottomClass: function() {
return ((this.vsplitterOffset - this.selfOffsetTop) <= Math.floor(this.availHeight/2))
? 'top'
: 'bottom';
},
topheightcss: function() {
return this.topheight + 'px';
},
bottomheightcss: function() {
return this.bottomheight + 'px';
}
}
};
+110 -52
View File
@@ -7,58 +7,7 @@ $(document).ready(function ()
var personid = $("#hiddenpersonid").val();
//add click events to "formal geprüft" checkboxes
$(".prchbox").click(function ()
{
var boxid = this.id;
var akteid = InfocenterDetails._getPrestudentIdFromElementId(boxid);
var checked = this.checked;
DocUeberpruefung.saveFormalGeprueft(personid, akteid, checked)
});
$('select.aktenid').change(function()
{
var akteid = InfocenterDetails._getPrestudentIdFromElementId(this.id);
var typ = $(this).val();
DocUeberpruefung.saveDocTyp(personid, akteid, typ);
});
$('.nachreichungInfos').click(function()
{
var akteid = InfocenterDetails._getPrestudentIdFromElementId(this.id);
DocUeberpruefung.checkNachreichungInputs(akteid);
});
$('.nachreichungAbbrechen').click(function()
{
var akteid = InfocenterDetails._getPrestudentIdFromElementId(this.id);
DocUeberpruefung.checkNachreichungInputs(akteid);
});
$('.nachreichungSpeichern').click(function()
{
var akteid = InfocenterDetails._getPrestudentIdFromElementId(this.id);
var typ = $('#aktenid_' + akteid).val();
var nachreichungAm = $('#nachreichungAm_' + akteid).val();
var nachreichungAnmerkung = $('#nachreichungAnmerkung_' + akteid).val();
if(nachreichungAm === '')
{
FHC_DialogLib.alertError(FHC_PhrasesLib.t('infocenter', 'datumUngueltig'));
return false;
}
var regEx = /^\d{2}\.\d{2}\.(\d{2}|\d{4})$/;
if(nachreichungAm.match(regEx) === null)
{
FHC_DialogLib.alertError(FHC_PhrasesLib.t('infocenter', 'datumUngueltig'))
return false;
}
DocUeberpruefung.saveNachreichung(personid, nachreichungAm, nachreichungAnmerkung, typ);
})
DocUeberpruefung._addDocUeberpruefungEvents(personid)
});
var DocUeberpruefung = {
@@ -158,6 +107,33 @@ var DocUeberpruefung = {
);
},
deleteDoc: function(personid, akteid)
{
FHC_AjaxClient.ajaxCallPost(
CALLED_PATH + "/deleteDoc/" + encodeURIComponent(personid),
{
"akteid": akteid
},
{
successCallback: function(data, textStatus, jqXHR) {
if (FHC_AjaxClient.isSuccess(data))
{
DocUeberpruefung._refreshUbersichtDoks();
InfocenterDetails._refreshLog();
}
else
{
FHC_DialogLib.alertError(FHC_AjaxClient.getError(data));
}
},
errorCallback: function(data)
{
FHC_DialogLib.alertWarning("Fehler beim Speichern!");
}
}
);
},
checkNachreichungInputs: function(akteid)
{
var inputs = $('#nachreichungInputs_' + akteid);
@@ -197,6 +173,19 @@ var DocUeberpruefung = {
}
},
_refreshUbersichtDoks: function()
{
var personid = $("#hiddenpersonid").val();
$("#uebersichtDoks").load(
CONTROLLER_URL + '/reloadUebersichtDoks/' + personid + '?fhc_controller_id=' + FHC_AjaxClient.getUrlParameter('fhc_controller_id'),
function () {
DocUeberpruefung._formatDocTable();
DocUeberpruefung._addDocUeberpruefungEvents(personid);
}
);
},
_refreshNachzureichendeDoks: function()
{
var personid = $("#hiddenpersonid").val();
@@ -205,10 +194,79 @@ var DocUeberpruefung = {
CONTROLLER_URL + '/reloadDoks/' + personid + '?fhc_controller_id=' + FHC_AjaxClient.getUrlParameter('fhc_controller_id'),
function () {
DocUeberpruefung._formatDocTable();
DocUeberpruefung._addDocUeberpruefungEvents(personid);
}
);
},
_addDocUeberpruefungEvents: function(personid)
{
//add click events to "formal geprüft" checkboxes
$(".prchbox").click(function ()
{
var boxid = this.id;
var akteid = InfocenterDetails._getPrestudentIdFromElementId(boxid);
var checked = this.checked;
DocUeberpruefung.saveFormalGeprueft(personid, akteid, checked)
});
$('select.aktenid').change(function()
{
var akteid = InfocenterDetails._getPrestudentIdFromElementId(this.id);
var typ = $(this).val();
DocUeberpruefung.saveDocTyp(personid, akteid, typ);
});
$('.nachreichungInfos').click(function()
{
var akteid = InfocenterDetails._getPrestudentIdFromElementId(this.id);
DocUeberpruefung.checkNachreichungInputs(akteid);
});
$('.nachreichungAbbrechen').click(function()
{
var akteid = InfocenterDetails._getPrestudentIdFromElementId(this.id);
DocUeberpruefung.checkNachreichungInputs(akteid);
});
$('.nachreichungSpeichern').click(function()
{
var akteid = InfocenterDetails._getPrestudentIdFromElementId(this.id);
var typ = $('#aktenid_' + akteid).val();
var nachreichungAm = $('#nachreichungAm_' + akteid).val();
var nachreichungAnmerkung = $('#nachreichungAnmerkung_' + akteid).val();
if(nachreichungAm === '')
{
FHC_DialogLib.alertError(FHC_PhrasesLib.t('infocenter', 'datumUngueltig'));
return false;
}
var regEx = /^\d{2}\.\d{2}\.(\d{2}|\d{4})$/;
if(nachreichungAm.match(regEx) === null)
{
FHC_DialogLib.alertError(FHC_PhrasesLib.t('infocenter', 'datumUngueltig'))
return false;
}
DocUeberpruefung.saveNachreichung(personid, nachreichungAm, nachreichungAnmerkung, typ);
})
$('.dokLoeschen').click(function()
{
var akteid = InfocenterDetails._getPrestudentIdFromElementId(this.id);
var confirmed = confirm('Wollen Sie sicher das Dokument des Dokumentypens: ' + $('#aktenid_' + akteid).find(':selected').text() + ' löschen?');
if (confirmed)
{
DocUeberpruefung.deleteDoc(personid, akteid);
}
});
},
_formatDocTable: function()
{
Tablesort.addTablesorter("doctable", [[2, 1], [1, 0]], ["zebra"]);
+9 -3
View File
@@ -150,6 +150,12 @@ var InfocenterDetails = {
if (FHC_AjaxClient.hasData(data))
{
var prestudent = data.retval[0];
if (prestudent.zgv_code === null && prestudent.zgvmas_code === null)
{
btn.after("<span id='zgvUebernehmenNotice' class='text-warning'>&nbsp;&nbsp;keine ZGV vorhanden</span>");
}
var zgvcode = prestudent.zgv_code !== null ? prestudent.zgv_code : "null";
var zgvort = prestudent.zgvort !== null ? prestudent.zgvort : "";
var zgvdatum = prestudent.zgvdatum;
@@ -183,7 +189,7 @@ var InfocenterDetails = {
}
else
{
btn.after("&nbsp;&nbsp;<span id='zgvUebernehmenNotice' class='text-warning'>keine ZGV vorhanden</span>");
btn.after("<span id='zgvUebernehmenNotice' class='text-warning'>&nbsp;&nbsp;Fehler beim Laden der Daten</span>");
}
},
errorCallback: function()
@@ -543,8 +549,8 @@ var InfocenterDetails = {
var prestudentdata = prestudentresponse.retval;
var prestudent_id = freigabedata.prestudent_id;
var statusgrund_id = freigabedata.statusgrund_id;
var prestudent_id = parseInt(freigabedata.prestudent_id);
var statusgrund_id = parseInt(freigabedata.statusgrund_id);
var rtfreigabe = !$.isNumeric(statusgrund_id);//no Statusgrund - RT Freigabe
var rtFreigegeben = false;
+46 -36
View File
@@ -34,11 +34,10 @@ var InfocenterPersonDataset = {
var auswahlStudienart =
'<select class="form-control auswahlStudienArt" style="width:auto;">' +
'<option data-id="all"> Alle </option>' +
'<option data-id="master"> Master </option>' +
'<option data-id="bachelor"> Bachelor </option>' +
'</select>';
InfocenterPersonDataset.getStudienartData(infocenter_studiengangstyp);
var auswahlAbsageToggle =
'<a class="absageToggle">Erweiterte Einstellungen</a>';
@@ -90,11 +89,9 @@ var InfocenterPersonDataset = {
"<div class='h-divider'></div><hr class='studiensemesterline'>"
);
InfocenterPersonDataset.selectStudiengangTyp(infocenter_studiengangstyp)
$('.auswahlStudienArt').change(function()
{
InfocenterPersonDataset.changeStudengangsTyp($(this).find('option:selected').attr('data-id'));
InfocenterPersonDataset.changeStudengangsTyp($(this).find('option:selected').val());
});
$("#datasetActionsBottom").append(
@@ -183,22 +180,6 @@ var InfocenterPersonDataset = {
);
},
selectStudiengangTyp: function(typ)
{
switch (typ)
{
case 'b, m' :
$('.auswahlStudienArt [data-id="all"]').attr('selected', 'selected');
break;
case 'b' :
$('.auswahlStudienArt [data-id="bachelor"]').attr('selected', 'selected');
break;
case 'm' :
$('.auswahlStudienArt [data-id="master"]').attr('selected', 'selected');
break;
}
},
/**
* sets functionality for the actions above and beneath the person table
*/
@@ -257,20 +238,12 @@ var InfocenterPersonDataset = {
});
},
changeStudengangsTyp: function($typ)
changeStudengangsTyp: function(typ)
{
switch ($typ)
{
case 'all' :
var change = 'b\', \'m';
break;
case 'bachelor' :
var change = 'b';
break;
case 'master' :
var change = 'm';
break;
}
let change = typ;
if (typ === 'all')
change = change = 'b\', \'m\', \'l';
FHC_AjaxClient.showVeil();
@@ -372,7 +345,8 @@ var InfocenterPersonDataset = {
'system/infocenter/InfoCenter/getAbsageData',
{},
{
successCallback: function(data, textStatus, jqXHR) {
successCallback: function(data, textStatus, jqXHR)
{
if (FHC_AjaxClient.hasData(data))
{
data = FHC_AjaxClient.getData(data);
@@ -397,6 +371,42 @@ var InfocenterPersonDataset = {
}
);
},
getStudienartData: function(infocenter_studiengangstyp)
{
FHC_AjaxClient.ajaxCallGet(
'system/infocenter/InfoCenter/getStudienartData',
{},
{
successCallback: function(data, textStatus, jqXHR)
{
if (FHC_AjaxClient.hasData(data))
{
data = FHC_AjaxClient.getData(data);
let all = data.map(item => item.typ).join('\',\'');
$('.auswahlStudienArt').append($("<option/>")
.val(all)
.text('Alle')
);
$.each(data, function(key, value)
{
let isSelected;
isSelected = (infocenter_studiengangstyp === value.typ && all.length !== 1) ? 'selected' : false;
$('.auswahlStudienArt').append($("<option/>")
.val(value.typ)
.text(value.bezeichnung)
.attr('selected', isSelected)
)
});
}
},
errorCallback: function(jqXHR, textStatus, errorThrown) {
FHC_DialogLib.alertError(textStatus);
}
}
);
},
/**
* initializes call to get the Studiensemester user variable
*/
+208
View File
@@ -0,0 +1,208 @@
$(document).ready(function ()
{
var personid = $("#hiddenpersonid").val();
$('.editStammdaten').click(function()
{
Stammdaten._show();
});
$('.cancelStammdaten').click(function()
{
Stammdaten._hide();
});
$('.saveStammdaten').click(function()
{
var kontakt = [];
$('.kontakt_input').each(function(){
kontakt.push({
id: $(this).data('id'),
value: $(this).val()
});
});
var adresse = [];
$('.adresse').each(function(){
var id = $(this).data('id');
adresse.push({
id: id,
value: {
'strasse': $('#strasse_' + id).val(),
'plz': $('#plz_' + id).val(),
'ort': $('#ort_' + id).val(),
'nation': $('#nation_' + id).val(),
}
});
});
var data = {
"personid" : personid,
"titelpre" : $('#titelpre_input').val(),
"vorname" : $('#vorname_input').val(),
"nachname" : $('#nachname_input').val(),
"titelpost" : $('#titelpost_input').val(),
"gebdatum" : $('#gebdatum_input').val(),
"svnr" : $('#svnr_input').val(),
"buergerschaft" : $('#buergerschaft').val(),
"geschlecht" : $('#geschlecht').val(),
"gebnation" : $('#gebnation').val(),
"gebort" : $('#gebort_input').val(),
"kontakt" : kontakt,
"adresse" : adresse,
};
Stammdaten.update(personid, data);
});
});
var Stammdaten = {
update: function(personid, data)
{
FHC_AjaxClient.ajaxCallPost(
CALLED_PATH + "/updateStammdaten/",
data,
{
successCallback: function(data, textStatus, jqXHR) {
if (FHC_AjaxClient.isSuccess(data))
{
FHC_DialogLib.alertSuccess("Done!");
Stammdaten._updated();
}
else
{
FHC_DialogLib.alertError(FHC_AjaxClient.getError(data));
}
},
errorCallback: function() {
FHC_DialogLib.alertWarning("Fehler beim Speichern!");
}
}
);
},
_hide: function()
{
$('.stammdaten_input').each(function(){
$(this).parent('td').children('div').show();
$(this).remove();
});
$('.kontakt_input').each(function(){
$(this).parent('td').children('span').show();
$(this).remove();
});
$('.adresse_input').each(function(){
$(this).parent('div').children('div').show();
$(this).remove();
});
Stammdaten._setReadOnly(true);
},
_show: function()
{
$('.stammdaten').each(function() {
var id = $(this).attr('id');
var input = $('<input />');
input.attr('id', id + '_input');
input.addClass('form-control stammdaten_input');
input.val($(this).html());
$(this).hide();
$(this).parent('td').append(input);
});
$('.kontakt').each(function() {
var id = $(this).data('id');
var value = $(this).data('value');
$(this).hide();
var input = $('<input />');
input.attr('data-id', id);
input.attr('value', value);
input.addClass('form-control kontakt_input');
input.val(value);
$(this).parent('td').append(input);
});
$('.adresse').each(function() {
var adressenID = $(this).data('id');
$($(this).children('div').get().reverse()).each(function() {
$(this).hide();
var type = $(this).data('type');
var value = $(this).data('value');
var input = $('<input />');
input.attr('data-type', type);
input.attr('id', type + '_' + adressenID);
input.attr('value', value);
input.attr('placeholder', type.toUpperCase());
input.addClass('form-control adresse_input');
input.val(value);
$(this).parent().prepend(input);
});
});
Stammdaten._setReadOnly(false);
},
_updated: function()
{
$('.kontakt_input').each(function() {
var span = $(this).parent('td').children('span');
var value = $(this).val();
var oldSpanValue = span.data('value');
span.data('value', value);
var newhtml = span.html().replace(oldSpanValue, value);
span.html(newhtml);
if (span.hasClass('email'))
span.find('a').attr('href', 'mailto:' + value);
span.show();
$(this).remove();
});
$('.adresse').each(function() {
$(this).children('input').each(function() {
var value = $(this).val();
var type = $(this).data('type');
var div = $('div[data-type="' + type + '"]');
div.data('value', value);
div.html(value);
div.show();
$(this).remove();
});
});
$('.stammdaten_input').each(function() {
var div = $(this).parent('td').children('div');
var value = $(this).val();
div.html(value);
div.show();
$(this).remove();
});
Stammdaten._setReadOnly(true);
},
_setReadOnly: function(readonly)
{
var stammdatenform = $('.stammdaten_form');
stammdatenform.find('select').attr('disabled', readonly);
if (readonly === true)
{
$('.editActionStammdaten').hide();
$('.editStammdaten').show();
}
else
{
$('.editActionStammdaten').show();
$('.editStammdaten').hide();
}
}
}
+65 -59
View File
@@ -3,12 +3,13 @@
*/
var IssuesDataset = {
// number of max issue ids that can be sent in one request for status change
maxIssuesPerRequest: 1000,
/**
* adds person table additional actions html (above and beneath it)
*/
appendTableActionsHtml: function()
{
appendTableActionsHtml: function() {
let auswahlStatus =
'<div class="input-group">' +
'<select class="form-control d-inline auswahlStatus">' +
@@ -78,69 +79,74 @@ var IssuesDataset = {
/**
* sets functionality for the actions above and beneath the person table
*/
setTableActions: function()
{
$(".setStatus").click(function()
setTableActions: function() {
$(".setStatus").click(function() {
let status_kurzbz = $(".auswahlStatus").val();
let issue_ids_sel = $("#filterTableDataset input:checked[name=issue_id\\[\\]]");
if(status_kurzbz.length <= 0)
return FHC_DialogLib.alertInfo(FHC_PhrasesLib.t("fehlermonitoring", "bitteStatusWaehlen"));
if(issue_ids_sel.length <= 0)
return FHC_DialogLib.alertInfo(FHC_PhrasesLib.t("fehlermonitoring", "bitteFehlerWaehlen"));
let issue_ids = [];
for (let i = 0; i < issue_ids_sel.length; i++)
{
let status_kurzbz = $(".auswahlStatus").val();
let issue_ids_sel = $("#filterTableDataset input:checked[name=issue_id\\[\\]]");
if(status_kurzbz.length <= 0)
return FHC_DialogLib.alertInfo(FHC_PhrasesLib.t("fehlermonitoring", "bitteStatusWaehlen"));
if(issue_ids_sel.length <= 0)
return FHC_DialogLib.alertInfo(FHC_PhrasesLib.t("fehlermonitoring", "bitteFehlerWaehlen"));
let issue_ids = [];
for (let i = 0; i < issue_ids_sel.length; i++)
{
issue_ids.push($(issue_ids_sel[i]).val());
}
FHC_AjaxClient.ajaxCallPost(
'system/issues/Issues/changeIssueStatus',
{
"issue_ids": issue_ids,
"status_kurzbz": status_kurzbz
},
{
successCallback: function(data, textStatus, jqXHR) {
if (FHC_AjaxClient.isError(data))
{
FHC_DialogLib.alertError(
FHC_PhrasesLib.t("fehlermonitoring", "statusAendernFehler") + ": "
+ FHC_AjaxClient.getError(data)
);
}
else if (FHC_AjaxClient.hasData(data))
{
FHC_FilterWidget.reloadDataset();
FHC_DialogLib.alertSuccess(FHC_AjaxClient.getData(data));
}
else
FHC_DialogLib.alertError(FHC_PhrasesLib.t("fehlermonitoring", "statusAendernUnbekannterFehler"));
},
errorCallback: function(jqXHR, textStatus, errorThrown) {
FHC_DialogLib.alertError(FHC_PhrasesLib.t("fehlermonitoring", "statusAendernFehler") + ": " + textStatus);
}
}
);
issue_ids.push($(issue_ids_sel[i]).val());
}
);
$(".selectAll").click(function()
{
//select only trs if not filtered by tablesorter
var trs = $("#filterTableDataset tbody tr").not(".filtered");
trs.find("input[name=issue_id\\[\\]]").prop("checked", true);
}
);
IssuesDataset.changeIssueStatus(issue_ids, status_kurzbz);
});
$(".unselectAll").click(function()
{
$(".selectAll").click(function() {
//select only trs if not filtered by tablesorter
var trs = $("#filterTableDataset tbody tr").not(".filtered");
trs.find("input[name=issue_id\\[\\]]").prop("checked", true);
});
$(".unselectAll").click(function() {
var trs = $("#filterTableDataset tbody tr").not(".filtered");
trs.find("input[name=issue_id\\[\\]]").prop("checked", false);
});
},
/**
* sends request for changing issue status
*/
changeIssueStatus: function(issue_ids, status_kurzbz) {
FHC_AjaxClient.ajaxCallPost(
'system/issues/Issues/changeIssueStatus',
{
// split up issue ids if too much data for single request
"issue_ids": issue_ids.slice(0, IssuesDataset.maxIssuesPerRequest),
"status_kurzbz": status_kurzbz
},
{
successCallback: function(data, textStatus, jqXHR) {
if (FHC_AjaxClient.isError(data))
{
FHC_DialogLib.alertError(
FHC_PhrasesLib.t("fehlermonitoring", "statusAendernFehler") + ": "
+ FHC_AjaxClient.getError(data)
);
}
else if (FHC_AjaxClient.hasData(data))
{
if (issue_ids.length < IssuesDataset.maxIssuesPerRequest)
{
FHC_DialogLib.alertSuccess(FHC_AjaxClient.getData(data));
FHC_FilterWidget.reloadDataset();
}
else // send next chunk of data
IssuesDataset.changeIssueStatus(issue_ids.slice(IssuesDataset.maxIssuesPerRequest), status_kurzbz);
}
else
FHC_DialogLib.alertError(FHC_PhrasesLib.t("fehlermonitoring", "statusAendernUnbekannterFehler"));
},
errorCallback: function(jqXHR, textStatus, errorThrown) {
FHC_DialogLib.alertError(FHC_PhrasesLib.t("fehlermonitoring", "statusAendernFehler") + ": " + textStatus);
}
}
);
}
+451
View File
@@ -0,0 +1,451 @@
/**
* Javascript file for Issues Zuständigkeiten assignment page
*/
const FEHLERAPP_DROPDOWN_ID = "fehlerappSelect";
const FEHLERCODE_DROPDOWN_ID = "fehlercodeSelect";
const MITARBEITER_AUTOCOMPLETE_ID = "mitarbeiterSelect";
const MITARBEITER_HIDDENFIELD_ID = "mitarbeiter_person_id";
const ORGANISATIONSEINHEIT_DROPDOWN_ID = "oeSelect";
const FUNKTION_DROPDOWN_ID = "funktionSelect";
var IssuesZustaendigkeiten = {
fehlercodesArr: [], // for saving received fehlercodes
oefunktionen: [], // for saving assigned oes and their funktionen
getApps: function()
{
FHC_AjaxClient.ajaxCallGet(
'system/issues/IssuesZustaendigkeiten/getApps',
null,
{
successCallback: function(data, textStatus, jqXHR) {
if (FHC_AjaxClient.hasData(data))
{
// save loaded apps
let apps = FHC_AjaxClient.getData(data);
// fill dropdown with apps
IssuesZustaendigkeiten._fillDropdown(
FEHLERAPP_DROPDOWN_ID,
"app",
apps,
null,
false,
"core"
);
// Initiate getting of fehlercodes with apps
IssuesZustaendigkeiten.getFehlercodes($("#"+FEHLERAPP_DROPDOWN_ID).val());
}
},
errorCallback: function(jqXHR, textStatus, errorThrown) {
FHC_DialogLib.alertError(textStatus);
}
}
);
},
getFehlercodes: function(app)
{
FHC_AjaxClient.ajaxCallGet(
'system/issues/IssuesZustaendigkeiten/getFehlercodes',
{
app: app
},
{
successCallback: function(data, textStatus, jqXHR) {
if (FHC_AjaxClient.hasData(data))
{
let fehlerCodesData = FHC_AjaxClient.getData(data);
// save fehlercodes data for displaying info later
IssuesZustaendigkeiten.fehlercodesArr = fehlerCodesData;
// display fehlercodes in dropdown
let fehlerCodes = [];
for (let i = 0; i < fehlerCodesData.length; i++)
{
let code = fehlerCodesData[i];
fehlerCodes.push(
{
fehlercode: code.fehlercode,
fullFehlerBezeichnung: code.fehlercode + (!code.fehler_kurzbz ? '' : ' - ' + code.fehler_kurzbz)
}
);
}
IssuesZustaendigkeiten._fillDropdown(
FEHLERCODE_DROPDOWN_ID,
"fehlercode",
fehlerCodes,
"fullFehlerBezeichnung"
);
// initiate call for getting Zuständigkeiten
IssuesZustaendigkeiten.getNonAssignedZustaendigkeiten($("#"+FEHLERCODE_DROPDOWN_ID).val());
}
},
errorCallback: function(jqXHR, textStatus, errorThrown) {
FHC_DialogLib.alertError(textStatus);
}
}
);
},
getNonAssignedZustaendigkeiten: function(fehlercode)
{
FHC_AjaxClient.ajaxCallGet(
'system/issues/IssuesZustaendigkeiten/getNonAssignedZustaendigkeiten',
{
fehlercode: fehlercode
},
{
successCallback: function(data, textStatus, jqXHR) {
if (FHC_AjaxClient.hasData(data))
{
// save loaded data
let zustaendigkeitenData = FHC_AjaxClient.getData(data);
// save in object to display correct funktionen when oe is changed
IssuesZustaendigkeiten.oe_funktionen = zustaendigkeitenData.oe_funktionen;
let zustaendigkeiten = [];
for (let i = 0; i < zustaendigkeitenData.oe_funktionen.length; i++)
{
let zustaendigkeit = zustaendigkeitenData.oe_funktionen[i];
zustaendigkeiten.push(
{
oe_kurzbz: zustaendigkeit.oe_kurzbz,
fullOeBezeichnung: zustaendigkeit.organisationseinheittyp_kurzbz + ' ' + zustaendigkeit.bezeichnung
}
);
}
// fill oe dropdown with data
IssuesZustaendigkeiten._fillDropdown(
"oeSelect",
"oe_kurzbz",
zustaendigkeiten,
"fullOeBezeichnung",
true
);
// fill funktion dropdown with data
IssuesZustaendigkeiten._fillFunktionDropdown();
// save Mitarbeiter data for autocomplete field in array
let autocompleteMitarbeiterArr = [];
for (let i = 0; i < zustaendigkeitenData.mitarbeiter.length; i++)
{
let ma = zustaendigkeitenData.mitarbeiter[i];
autocompleteMitarbeiterArr.push(
{
vorname: ma.vorname,
nachname: ma.nachname,
uid: ma.uid,
label: ma.nachname + " " + ma.vorname + " (" + ma.uid + ")",
id: ma.person_id
}
);
}
// callback for searching source mitarbeiter array correctly
let sourceCallback = function(request, response)
{
// case insensitive matcher
var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
// match vorname nachname OR nachname vorname OR uid
response($.grep(autocompleteMitarbeiterArr, function (value) {
return matcher.test(value.nachname + ' '+value.vorname + ' ' + value.nachname)
|| matcher.test(value.uid);
}));
}
// fill autocomplete field with mitarbeiter data
IssuesZustaendigkeiten._fillAutocomplete(
MITARBEITER_AUTOCOMPLETE_ID,
MITARBEITER_HIDDENFIELD_ID,
sourceCallback
);
// set events on delete buttons
$(".deleteBtn").click(
function()
{
IssuesZustaendigkeiten.deleteZustaendigkeit($(this).prop("id"));
}
)
}
},
errorCallback: function(jqXHR, textStatus, errorThrown) {
FHC_DialogLib.alertError(textStatus);
}
}
);
},
addZustaendigkeit: function(data)
{
FHC_AjaxClient.ajaxCallPost(
'system/issues/IssuesZustaendigkeiten/addZustaendigkeit',
data,
{
successCallback: function(data, textStatus, jqXHR) {
if (FHC_AjaxClient.hasData(data))
{
// show message, reset input fields and reload data after Zuständigkeit added
FHC_DialogLib.alertSuccess(FHC_PhrasesLib.t('fehlermonitoring', 'zustaendigkeitGespeichert'))
IssuesZustaendigkeiten._emptyInputFields();
FHC_FilterWidget.reloadDataset();
}
else
{
// show error if no data
let errorMsg = FHC_PhrasesLib.t('fehlermonitoring', 'zustaendigkeitGespeichertFehler');
if (FHC_AjaxClient.isError(data))
errorMsg += ": "+FHC_AjaxClient.getError(data);
FHC_DialogLib.alertError(errorMsg);
}
},
errorCallback: function(jqXHR, textStatus, errorThrown) {
FHC_DialogLib.alertError(textStatus);
}
}
);
},
deleteZustaendigkeit: function(fehlerzustaendigkeiten_id)
{
FHC_AjaxClient.ajaxCallPost(
'system/issues/IssuesZustaendigkeiten/deleteZustaendigkeit',
{
fehlerzustaendigkeiten_id: fehlerzustaendigkeiten_id
},
{
successCallback: function(data, textStatus, jqXHR) {
if (FHC_AjaxClient.hasData(data))
{
FHC_DialogLib.alertSuccess(FHC_PhrasesLib.t('fehlermonitoring', 'zustaendigkeitGeloescht'))
// reload dataset to see change
FHC_FilterWidget.reloadDataset();
}
else
{
FHC_DialogLib.alertError(FHC_PhrasesLib.t('fehlermonitoring', 'zustaendigkeitGeloeschtFehler'));
}
},
errorCallback: function(jqXHR, textStatus, errorThrown) {
FHC_DialogLib.alertError(textStatus);
}
}
);
},
_fillFunktionDropdown: function()
{
let funktionen = [];
let oe_kurzbz = $("#"+ORGANISATIONSEINHEIT_DROPDOWN_ID).val();
// get funktionen for selected oe (saved in js object)
for (let i = 0; i < IssuesZustaendigkeiten.oe_funktionen.length; i++)
{
let oe_funktion = IssuesZustaendigkeiten.oe_funktionen[i];
if (oe_funktion.oe_kurzbz === oe_kurzbz)
{
funktionen = oe_funktion.funktionen
break;
}
}
IssuesZustaendigkeiten._fillDropdown(
"funktionSelect",
"funktion_kurzbz",
funktionen,
"beschreibung",
true
);
},
_fillDropdown: function(dropdownId, valueName, data, textName, includeNoSelectionOption, defaultValue)
{
// by default, displayed text in dropdown is the value
if (!textName)
textName = valueName;
// clear dropdown
$("#"+dropdownId).empty();
// optionally include default "no selection" value
if (includeNoSelectionOption === true)
$("#"+dropdownId).append("<option value=''> -- "+FHC_PhrasesLib.t('fehlermonitoring', 'keineAuswahl')+" -- </option>");
// fill dropdown with values
for (let i = 0; i < data.length; i++)
{
let val = data[i];
// the value selected by default
let selected = val === defaultValue ? " selected" : "";
// append option
$("#"+dropdownId).append("<option value='"+val[valueName]+"'"+selected+">"+val[textName]+"</option>");
}
},
_fillAutocomplete: function(autocompleteId, idFieldId, source)
{
// jQuery ui autocomplete for employees
$("#"+autocompleteId).autocomplete(
{
// custom matcher
source: source,
autoFocus: true,
select: function(event, ui)
{
// when autocmplete entry selected, display label text in autocomplete, fill hidden value field
$("#"+autocompleteId).val(ui.item.label);
$("#"+idFieldId).val(ui.item.id);
return false;
}
}
);
},
_toggleFieldDisability: function()
{
let oeDropdownEl = $("#"+ORGANISATIONSEINHEIT_DROPDOWN_ID);
let funktionDropdownEl = $("#"+FUNKTION_DROPDOWN_ID);
let maAutocompleteEl = $("#"+MITARBEITER_AUTOCOMPLETE_ID);
let maHiddenEl = $("#"+MITARBEITER_HIDDENFIELD_ID);
// if Mitarbeiter is entered
if (maAutocompleteEl.val().length > 0)
{
// disable oe and funktion input
oeDropdownEl.prop('disabled', true);
oeDropdownEl.val('');
funktionDropdownEl.prop('disabled', true);
}
else
{
// otherwise enable oe input if Mitarbeiter input empty
oeDropdownEl.prop('disabled', false);
}
// if oe is entered
if (oeDropdownEl.val().length > 0)
{
// disable Mitarbeiter input
maAutocompleteEl.prop('disabled', true);
maAutocompleteEl.val('');
maHiddenEl.val('');
// enable funktion input
funktionDropdownEl.prop('disabled', false);
IssuesZustaendigkeiten._fillFunktionDropdown();
}
else
{
// otherwise enable mitarbeiter input
maAutocompleteEl.prop('disabled', false);
// disable funktion input
funktionDropdownEl.prop('disabled', true);
}
},
_emptyInputFields: function()
{
// clear all input fields
$("#"+MITARBEITER_AUTOCOMPLETE_ID).val('');
$("#"+MITARBEITER_HIDDENFIELD_ID).val('');
$("#"+ORGANISATIONSEINHEIT_DROPDOWN_ID).val('');
$("#"+FUNKTION_DROPDOWN_ID).val('');
}
};
/**
* When JQuery is up
*/
$(document).ready(function() {
// initiate cascade of getting data, first apps
IssuesZustaendigkeiten.getApps();
// get new fehlercodes each time app is changed
$("#"+FEHLERAPP_DROPDOWN_ID).change(
function()
{
IssuesZustaendigkeiten.getFehlercodes($(this).val());
}
);
// get new zustaendigkeiten every time Fehlercode is changed
$("#"+FEHLERCODE_DROPDOWN_ID).change(
function()
{
IssuesZustaendigkeiten.getNonAssignedZustaendigkeiten($(this).val());
}
);
// set events for disabling input fields
$("#"+MITARBEITER_AUTOCOMPLETE_ID).keyup(IssuesZustaendigkeiten._toggleFieldDisability);
$("#"+ORGANISATIONSEINHEIT_DROPDOWN_ID).change(IssuesZustaendigkeiten._toggleFieldDisability);
// set event for adding a new Zuständigkeit
$("#assignZustaendigkeit").click(
function()
{
let data = {
fehlercode: $("#"+FEHLERCODE_DROPDOWN_ID).val()
}
let mitarbeiter_person_id = $("#"+MITARBEITER_HIDDENFIELD_ID).val();
let oe_kurzbz = $("#"+ORGANISATIONSEINHEIT_DROPDOWN_ID).val();
// if person id set, send it, otherwise oe_kurzbz
if (mitarbeiter_person_id.length > 0)
data.mitarbeiter_person_id = mitarbeiter_person_id;
else if (oe_kurzbz.length > 0)
{
data.oe_kurzbz = oe_kurzbz
data.funktion_kurzbz = $("#"+FUNKTION_DROPDOWN_ID).val();
}
IssuesZustaendigkeiten.addZustaendigkeit(data);
}
)
// set event for showing info modal
$("#fehlercodeInfoCell").click(
function()
{
let fehlercode = $("#"+FEHLERCODE_DROPDOWN_ID).val();
let fehlercodeData = {};
for (let i = 0; i < IssuesZustaendigkeiten.fehlercodesArr.length; i++)
{
let fc = IssuesZustaendigkeiten.fehlercodesArr[i];
if (fc.fehlercode === fehlercode)
{
fehlercodeData = fc;
break;
}
}
if (!fehlercodeData)
return;
$("#fehlerInfoLabel").text(fehlercodeData.fehlercode + " - " + fehlercodeData.fehler_kurzbz);
$("#fehlercodeInfo").text(fehlercodeData.fehlercode);
$("#fehlerkurzbzInfo").text(fehlercodeData.fehler_kurzbz);
$("#fehlertypInfo").text(fehlercodeData.fehlertyp_kurzbz);
$("#fehlercodeExternInfo").text(fehlercodeData.fehlercode_extern ? fehlercodeData.fehlercode_extern : '-');
$("#fehlertextInfo").text(fehlercodeData.fehlertext);
$("#fehlerInfo").modal("show");
}
)
});
+67
View File
@@ -0,0 +1,67 @@
/**
* Javascript file for Plausichecks display
*/
var Plausichecks = {
startPlausichecks: function (studiensemester_kurzbz, studiengang_kz, fehler_kurzbz) {
FHC_AjaxClient.ajaxCallGet(
'system/issues/Plausichecks/runChecks',
{
studiensemester_kurzbz: studiensemester_kurzbz,
studiengang_kz: studiengang_kz,
fehler_kurzbz: fehler_kurzbz
},
{
successCallback: function (data, textStatus, jqXHR) {
if (FHC_AjaxClient.isError(data)) FHC_DialogLib.alertError(FHC_AjaxClient.getError(data));
let messageStr = "<strong>Plausichecks Prüfung Start</strong>";
if (FHC_AjaxClient.hasData(data))
{
let issueTexts = FHC_AjaxClient.getData(data);
for (let fehler_kurzbz in issueTexts)
{
messageStr += "<br /><br /><span>Prüfe " + fehler_kurzbz + "...</span>";
let texts = issueTexts[fehler_kurzbz];
if (texts.length == 0) {
messageStr += "<br /><span class='text-success'>Keine Issues für " + fehler_kurzbz + "</span>";
continue;
}
for (i = 0; i < texts.length; i++)
{
messageStr += "<br /><span class='text-danger'>" + texts[i] + "</span>";
}
}
}
messageStr += "<br /><br /><strong>Plausichecks Prüfung Ende</strong>";
$("#plausioutput").html(messageStr);
},
errorCallback: function (jqXHR, textStatus, errorThrown) {
FHC_DialogLib.alertError(textStatus);
}
}
);
},
};
/**
* When JQuery is up
*/
$(document).ready(function () {
// start the Plausicheck run on button click
$("#plausistart").click(
function () {
Plausichecks.startPlausichecks(
$("#studiensemester").val(),
$("#studiengang_kz").val(),
$("#fehler_kurzbz").val(),
);
}
)
});
@@ -4,8 +4,6 @@ const ANRECHNUNGSTATUS_PROGRESSED_BY_LEKTOR = 'inProgressLektor';
const ANRECHNUNGSTATUS_APPROVED = 'approved';
const ANRECHNUNGSTATUS_REJECTED = 'rejected';
$(function(){
const genehmigung_panel = $('#approveAnrechnungDetail-genehmigung-panel');
@@ -36,6 +34,8 @@ $(function(){
// Init tooltips
approveAnrechnungDetail.initTooltips();
approveAnrechnungDetail.alertIfMaxEctsExceeded();
// Ask if Approve Anrechnungen
$("#approveAnrechnungDetail-approve-anrechnung-ask").click(function(){
@@ -91,8 +91,12 @@ $(function(){
approveAnrechnungDetail.formatGenehmigungIsPositiv(
data.retval[0].abgeschlossen_am,
data.retval[0].abgeschlossen_von,
data.retval[0].status_bezeichnung
data.retval[0].status_kurzbz,
data.retval[0].status_bezeichnung,
);
approveAnrechnungDetail.sumUpEcts();
approveAnrechnungDetail.alertIfMaxEctsExceeded();
}
},
errorCallback: function (jqXHR, textStatus, errorThrown)
@@ -168,6 +172,7 @@ $(function(){
approveAnrechnungDetail.formatGenehmigungIsNegativ(
data.retval[0].abgeschlossen_am,
data.retval[0].abgeschlossen_von,
data.retval[0].status_kurzbz,
data.retval[0].status_bezeichnung,
begruendung
);
@@ -236,6 +241,7 @@ $(function(){
// Get form data
let form_data = $('form').serializeArray();
var init_status_kurzbz = $('#approveAnrechnungDetail-status_kurzbz').data('status_kurzbz');
// Prepare data object for ajax call
let data = {
@@ -248,21 +254,24 @@ $(function(){
{
successCallback: function (data, textStatus, jqXHR)
{
console.log(data);
if (data.error && data.retval != null)
{
console.log('inside error');
// Print error message
FHC_DialogLib.alertWarning(data.retval);
}
if (!data.error && data.retval != null)
{
console.log('inside success');
approveAnrechnungDetail.formatGenehmigungIsWithdrawed(
data.retval.status_bezeichnung
);
if (init_status_kurzbz == 'approved')
{
approveAnrechnungDetail.substractEcts(ects, sumEctsSchulisch, sumEctsBeruflich);
approveAnrechnungDetail.alertIfMaxEctsExceeded();
}
FHC_DialogLib.alertSuccess(FHC_PhrasesLib.t("anrechnung", "erfolgreichZurueckgenommen"));
}
@@ -477,12 +486,13 @@ var approveAnrechnungDetail = {
$('#approveAnrechnungDetail-reject-anrechnung-ask').prop('disabled', true);
$('#approveAnrechnungDetail-withdraw-request-recommedation').removeClass('hidden');
},
formatGenehmigungIsPositiv: function(abgeschlossenAm, abgeschlossenVon, statusBezeichnung){
formatGenehmigungIsPositiv: function(abgeschlossenAm, abgeschlossenVon, statusKurzbz, statusBezeichnung){
$('#approveAnrechnungDetail-genehmigungDetail-genehmigungIsNull').addClass('hidden');
$('#approveAnrechnungDetail-genehmigungDetail-genehmigungIsNegativ').addClass('hidden');
$('#approveAnrechnungDetail-genehmigungDetail-genehmigungIsPositiv').removeClass('hidden');
$('#approveAnrechnungDetail-status_kurzbz').text(statusBezeichnung);
$('#approveAnrechnungDetail-status_kurzbz').closest('div').removeClass('alert-warning').addClass('alert-success');
$('#approveAnrechnungDetail-status_kurzbz').data('status_kurzbz', statusKurzbz);
$('#approveAnrechnungDetail-abgeschlossenAm').text(abgeschlossenAm);
$('#approveAnrechnungDetail-abgeschlossenVon').text(abgeschlossenVon);
$('#approveAnrechnungDetail-request-recommendation').prop('disabled', true);
@@ -492,12 +502,13 @@ var approveAnrechnungDetail = {
// Show button to withdraw approval
$('#approveAnrechnungDetail-withdraw-anrechnung-approvement').removeClass('hidden');
},
formatGenehmigungIsNegativ: function(abgeschlossenAm, abgeschlossenVon, statusBezeichnung, begruendung){
formatGenehmigungIsNegativ: function(abgeschlossenAm, abgeschlossenVon, statusKurzbz, statusBezeichnung, begruendung){
$('#approveAnrechnungDetail-genehmigungDetail-genehmigungIsNull').addClass('hidden');
$('#approveAnrechnungDetail-genehmigungDetail-genehmigungIsPositiv').addClass('hidden');
$('#approveAnrechnungDetail-genehmigungDetail-genehmigungIsNegativ').removeClass('hidden');
$('#approveAnrechnungDetail-status_kurzbz').text(statusBezeichnung);
$('#approveAnrechnungDetail-status_kurzbz').closest('div').removeClass('alert-warning').addClass('alert-danger');
$('#approveAnrechnungDetail-status_kurzbz').data('status_kurzbz', statusKurzbz);
$('#approveAnrechnungDetail-abgeschlossenAm').text(abgeschlossenAm);
$('#approveAnrechnungDetail-abgeschlossenVon').text(abgeschlossenVon);
$('#approveAnrechnungDetail-genehmigungDetail-begruendung').text(begruendung);
@@ -544,5 +555,77 @@ var approveAnrechnungDetail = {
$('#approveAnrechnungDetail-reject-anrechnung-ask').prop('disabled', false);
// Hide button to withdraw approval
$('#approveAnrechnungDetail-withdraw-request-recommedation').addClass('hidden');
},
sumUpEcts: function(){
var ects = parseFloat($('#ects').text());
var sumEctsSchulisch = parseFloat($('#sumEctsSchulisch').text());
var sumEctsBeruflich = parseFloat($('#sumEctsBeruflich').text());
var begruendung_id = $('#begruendung_id').data('begruendung_id');
if (begruendung_id == 5)
{
return;
}
if (begruendung_id == 4)
{
$('#sumEctsBeruflich').text(sumEctsBeruflich + ects);
}
else
{
$('#sumEctsSchulisch').text(sumEctsSchulisch + ects);
}
$('#sumEctsTotal').text(sumEctsSchulisch + sumEctsBeruflich + ects);
},
substractEcts: function(ects, sumEctsSchulisch, sumEctsBeruflich){
var ects = parseFloat($('#ects').text());
var sumEctsSchulisch = parseFloat($('#sumEctsSchulisch').text());
var sumEctsBeruflich = parseFloat($('#sumEctsBeruflich').text());
var begruendung_id = $('#begruendung_id').data('begruendung_id');
if (begruendung_id == 5)
{
return;
}
if (begruendung_id == 4)
{
$('#sumEctsBeruflich').text(sumEctsBeruflich - ects);
}
else
{
$('#sumEctsSchulisch').text(sumEctsSchulisch - ects);
}
$('#sumEctsTotal').text(sumEctsSchulisch + sumEctsBeruflich - ects);
},
alertIfMaxEctsExceeded: function(){
var begruendung_id = $('#begruendung_id').data('begruendung_id');
if (begruendung_id == 5)
{
return;
}
if (
(begruendung_id != 4 && (parseFloat($('#ects').text()) + parseFloat($('#sumEctsSchulisch').text()))) > 60 ||
(begruendung_id == 4 && (parseFloat($('#ects').text()) + parseFloat($('#sumEctsBeruflich').text()))) > 60 ||
(parseFloat($('#ects').text()) + parseFloat($('#sumEctsSchulisch').text()) + parseFloat($('#sumEctsBeruflich').text())) > 90
)
{
$('#sumEctsMsg')
.html("<br><b>ACHTUNG! Bei Anrechnung von LV: Überschreitung der Höchstgrenze für Anrechnungen gem. § 12 Abs. 3 Fachhochschulgesetz</b><i class=\"fa fa-lg fa-info-circle\"></i></br>")
.addClass('bg-danger text-danger')
.tooltip({
title: FHC_PhrasesLib.t("anrechnung", "anrechnungEctsTooltipTextBeiUeberschreitung"),
placement: 'right',
html: true
});
}
else
{
$('#sumEctsMsg').html('').css('border', 'none');
}
}
}
@@ -1,4 +1,6 @@
const BASE_URL = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
const CALLED_PATH = FHC_JS_DATA_STORAGE_OBJECT.called_path;
const CONTROLLER_URL = BASE_URL + '/' + CALLED_PATH;
const APPROVE_ANRECHNUNG_DETAIL_URI = "lehre/anrechnung/ApproveAnrechnungDetail";
const ANRECHNUNGSTATUS_PROGRESSED_BY_STGL = 'inProgressDP';
@@ -8,6 +10,12 @@ const ANRECHNUNGSTATUS_APPROVED = 'approved';
const ANRECHNUNGSTATUS_REJECTED = 'rejected';
const COLOR_LIGHTGREY = "#f5f5f5";
const COLOR_DANGER = '#f2dede';
var tabulator = null; // Set in tableBuilt function.
// Array with accumulated LV ECTS by Prestudent. Used to find out if max ECTS are exceeded.
var selectedPrestudentWithAccumulatedLvEcts = [];
// -----------------------------------------------------------------------------------------------------------------
// Mutators - setter methods to manipulate table data when entering the tabulator
@@ -52,6 +60,10 @@ function hf_filterTrueFalse(headerValue, rowValue){
// Adds column details
// Sets focus on filterbutton, if table starts with stored filter.
function func_tableBuilt(table) {
// Store table in global var
tabulator = table;
table.addColumn(
{
title: "Details",
@@ -66,7 +78,7 @@ function func_tableBuilt(table) {
},
target:"_blank"
}
}, false, "status" // place column after status
}, true // place column on the very left
);
// Set focus on filterbutton
@@ -76,16 +88,74 @@ function func_tableBuilt(table) {
}
}
/**
* Formats column ECTS (LV + Bisher).
*/
var format_ectsSumBisherUndNeu = function(cell, formatterParams, onRendered){
let row = cell.getRow();
let rowData = row.getData();
let begruendung_id = (rowData.begruendung_id);
let ectsSumBisherUndNeuTotal = (rowData.ectsSumSchulisch + rowData.ectsSumBeruflich);
let ectsSumBisherUndNeuSchulisch = rowData.ectsSumSchulisch;
let ectsSumBisherUndNeuBeruflich = rowData.ectsSumBeruflich;
// If exists, add accumulated LV ECTS to bisherige ECTS
if (selectedPrestudentWithAccumulatedLvEcts.length > 0)
{
let selectedPrestudent = selectedPrestudentWithAccumulatedLvEcts.find(x => x.prestudent_id === rowData.prestudent_id);
if (selectedPrestudent != undefined)
{
ectsSumBisherUndNeuTotal = (rowData.ectsSumSchulisch + rowData.ectsSumBeruflich) + selectedPrestudent.ectsSumAnzurechnendeLvsSchulisch + selectedPrestudent.ectsSumAnzurechnendeLvsBeruflich;
ectsSumBisherUndNeuSchulisch = rowData.ectsSumSchulisch + selectedPrestudent.ectsSumAnzurechnendeLvsSchulisch;
ectsSumBisherUndNeuBeruflich = rowData.ectsSumBeruflich + selectedPrestudent.ectsSumAnzurechnendeLvsBeruflich;
}
// Color column if maximum ECTS exceeded
if (begruendung_id != 5 && row.isSelected())
{
if (
(ectsSumBisherUndNeuSchulisch + ectsSumBisherUndNeuBeruflich) > 90 ||
ectsSumBisherUndNeuSchulisch > 60 ||
ectsSumBisherUndNeuBeruflich > 60
)
{
cell.getElement().style["background-color"] = COLOR_DANGER;
}
}
else
{
cell.getElement().style.removeProperty('background-color');
}
}
// If max ECTS is exceeded, format font color / weight
ectsSumBisherUndNeuTotal = (ectsSumBisherUndNeuTotal > 90) ? "<span class='text-danger'><b><u>" + ectsSumBisherUndNeuTotal + "</u></b></span>" : ectsSumBisherUndNeuTotal;
ectsSumBisherUndNeuSchulisch = (ectsSumBisherUndNeuSchulisch > 60) ? "<span class='text-danger'><b><u>" + ectsSumBisherUndNeuSchulisch + "</u></b></span>" : ectsSumBisherUndNeuSchulisch;
ectsSumBisherUndNeuBeruflich = (ectsSumBisherUndNeuBeruflich > 60) ? "<span class='text-danger'><b><u>" + ectsSumBisherUndNeuBeruflich + "</u></b></span>" : ectsSumBisherUndNeuBeruflich;
return "T: " + ectsSumBisherUndNeuTotal + " [ S: " + ectsSumBisherUndNeuSchulisch + " | B: " + ectsSumBisherUndNeuBeruflich + " ]";
}
// Formats the rows
function func_rowFormatter(row){
let status_kurzbz = row.getData().status_kurzbz;
row.getCells().forEach(function(cell){
if (status_kurzbz != ANRECHNUNGSTATUS_PROGRESSED_BY_STGL)
{
row.getElement().style["background-color"] = COLOR_LIGHTGREY; // default
}
});
// If status is anything else then 'Bearbeitet von STGL-Leitung'
if (status_kurzbz != ANRECHNUNGSTATUS_PROGRESSED_BY_STGL)
{
// Disable new selection of updated rows
row.getElement().style["pointerEvents"] = "none";
// ...but leave url links selectable
row.getCell('dokument_bezeichnung').getElement().firstChild.style["pointerEvents"] = "auto";
row.getCell('details').getElement().firstChild.style["pointerEvents"] = "auto";
// Color background grey
row.getElement().style["background-color"] = COLOR_LIGHTGREY; // default
}
}
// Formats row selectable/unselectable
@@ -99,18 +169,23 @@ function func_selectableCheck(row){
);
}
// Performes after row was updated
function func_rowUpdated(row){
// Refresh row formatters
row.reformat();
// Calculate dynamically sum of all LV ECTS by Student and display, when maximum ECTS are exceeded.
// data = selected data, rows = selected rows
function func_rowSelectionChanged(data, rows){
// Deselect and disable new selection of updated rows
row.deselect();
row.getElement().style["pointerEvents"] = "none";
// Sum up over all anzurechnenden LV-ECTS by Prestudent
selectedPrestudentWithAccumulatedLvEcts = approveAnrechnung.getSumLvEctsByPreStudent(data);
// ...but leave url links selectable
row.getCell('dokument_bezeichnung').getElement().firstChild.style["pointerEvents"] = "auto";
row.getCell('details').getElement().firstChild.style["pointerEvents"] = "auto";
// Loop through all active rows
var rowManager = tabulator.rowManager;
for (var i = 0; i < rowManager.activeRows.length; i++) {
// Reinitialize row -> triggers formatters.
rowManager.activeRows[i].reinitialize();
}
// Show number of selected rows.
approveAnrechnung.showNumberSelectedRows(rows);
}
// Returns tooltip
@@ -130,17 +205,30 @@ var format_empfehlung_anrechnung = function(cell, formatterParams){
: FHC_PhrasesLib.t("ui", "nein");
}
/**
* Returns formatter params for field dokument_bezeichnung (= Spalte Nachweisdokumente)
* NOTE: Returning a formatter param object fixes the problem, that tabulator did not know the url after refreshing the page.
*/
function paramLookup_dokBez(cell){
return {
labelField: 'dokument_bezeichnung',
url: CONTROLLER_URL + '/download?dms_id=' + cell.getData().dms_id,
target: '_blank'
}
}
/*
* Hook to overwrite TableWigdgets select-all-button behaviour
* Select all (filtered) rows that are progressed by stg leiter.
* (Ignore rows that are approved, rejected or in request for recommendation)
*/
function tableWidgetHook_selectAllButton(tableWidgetDiv){
tableWidgetDiv.find("#tableWidgetTabulator").tabulator('getRows', true)
var resultRows = tableWidgetDiv.find("#tableWidgetTabulator").tabulator('getRows', true)
.filter(row =>
row.getData().status_kurzbz == ANRECHNUNGSTATUS_PROGRESSED_BY_STGL
)
.forEach((row => row.select()));
);
tableWidgetDiv.find("#tableWidgetTabulator").tabulator('selectRow', resultRows);
}
@@ -275,13 +363,7 @@ $(function(){
e.stopImmediatePropagation();
// Get selected rows data
let selected_data = $('#tableWidgetTabulator').tabulator('getSelectedData')
.map(function(data){
// reduce to necessary fields
return {
'anrechnung_id' : data.anrechnung_id,
}
});
let selected_data = $('#tableWidgetTabulator').tabulator('getSelectedData');
// Alert and exit if no anrechnung is selected
if (selected_data.length == 0)
@@ -304,19 +386,70 @@ $(function(){
{
successCallback: function (data, textStatus, jqXHR)
{
if (data.error && data.retval != null)
if (FHC_AjaxClient.isError(data))
{
// Print error message
FHC_DialogLib.alertWarning(data.retval);
FHC_DialogLib.alertError(FHC_AjaxClient.getError(data));
}
if (!data.error && data.retval != null)
else if (FHC_AjaxClient.hasData(data))
{
// Update status 'genehmigt'
$('#tableWidgetTabulator').tabulator('updateData', data.retval);
data = FHC_AjaxClient.getData(data);
var prestudenten = Object.keys(data.prestudenten);
// Find intersection of selected and in fact updated Anrechnungen (in case server did not approve all).
var updatedData = selected_data.filter(x => prestudenten.some(prestudent => x.prestudent_id == prestudent));
// Sum up over all anzurechnenden LV-ECTS by Prestudent
var sumLvEctsByPrestudent = approveAnrechnung.getSumLvEctsByPreStudent(updatedData);
// Loop through Prestudenten
// key = Prestudent, value = Approved Anrechnungen of Prestudent
Object.entries(data.prestudenten).forEach(([key, value]) => {
var rowsToDeselect = [];
// Get accumulated sum of all LV ECTS
var sumLvEcts = sumLvEctsByPrestudent.find(x => x.prestudent_id == key);
// Get ALL rows of that Prestudent
var rows = $('#tableWidgetTabulator').tabulator('searchRows', 'prestudent_id', '=', key);
// Loop through the rows
rows.forEach(row => {
var updateData = {};
// If Anrechnung was approved...
if ((value.findIndex(anrechnung_id => row.getData().anrechnung_id == anrechnung_id)) !== -1)
{
// ...update status
updateData.status_kurzbz = data.status_kurzbz;
updateData.status_bezeichnung = data.status_bezeichnung;
// ...and store row to be deselected later on
rowsToDeselect.push(row);
}
// Update 'Bisher schulische ECTS' and 'Bisher berufliche ECTS' with the Sum of new approved ECTS
updateData.ectsSumSchulisch = row.getData().ectsSumSchulisch + sumLvEcts.ectsSumAnzurechnendeLvsSchulisch,
updateData.ectsSumBeruflich = row.getData().ectsSumBeruflich + sumLvEcts.ectsSumAnzurechnendeLvsBeruflich
// Update row
row.update(updateData);
// Reformat row
row.reformat();
})
// Deselect rows
$("#tableWidgetTabulator").tabulator('deselectRow', rowsToDeselect);
})
// Print success message
FHC_DialogLib.alertSuccess(FHC_PhrasesLib.t("ui", "anrechnungenWurdenGenehmigt"));
FHC_DialogLib.alertSuccess(FHC_PhrasesLib.t("ui", "anrechnungenWurdenGenehmigt"));
}
},
errorCallback: function (jqXHR, textStatus, errorThrown)
@@ -393,16 +526,21 @@ $(function(){
{
successCallback: function (data, textStatus, jqXHR)
{
if (data.error && data.retval != null)
if (FHC_AjaxClient.isError(data))
{
// Print error message
FHC_DialogLib.alertWarning(data.retval);
FHC_DialogLib.alertError(FHC_AjaxClient.getError(data));
}
if (!data.error && data.retval != null)
else if (FHC_AjaxClient.hasData(data))
{
data = FHC_AjaxClient.getData(data);
// Update status 'genehmigt'
$('#tableWidgetTabulator').tabulator('updateData', data.retval);
$('#tableWidgetTabulator').tabulator('updateData', data);
// Deselect rows
var indexesToDeselect = data.map(x => x.anrechnung_id);
$("#tableWidgetTabulator").tabulator('deselectRow', indexesToDeselect);
// Print success message
FHC_DialogLib.alertSuccess(FHC_PhrasesLib.t("ui", "anrechnungenWurdenAbgelehnt"));
@@ -457,20 +595,21 @@ $(function(){
{
successCallback: function (data, textStatus, jqXHR)
{
if (data.error && data.retval != null)
if (FHC_AjaxClient.isError(data))
{
// Print error message
FHC_DialogLib.alertWarning(data.retval);
FHC_DialogLib.alertError(FHC_AjaxClient.getError(data));
}
if (!data.error && data.retval != null)
else if (FHC_AjaxClient.hasData(data))
{
data = FHC_AjaxClient.getData(data);
// Print info message, if not all selected recommendations were requested
if (data.retval.length < selected_data.length){
if (data.length < selected_data.length){
FHC_DialogLib.alertInfo(
FHC_PhrasesLib.t(
"ui", "empfehlungWurdeAngefordertAusnahmeWoKeineLektoren",
[selected_data.length, data.retval.length, selected_data.length - data.retval.length])
[selected_data.length, data.length, selected_data.length - data.length])
);
}
else
@@ -481,7 +620,11 @@ $(function(){
}
//Update status 'genehmigt'
$('#tableWidgetTabulator').tabulator('updateData', data.retval);
$('#tableWidgetTabulator').tabulator('updateData', data);
// Deselect rows
var indexesToDeselect = data.map(x => x.anrechnung_id);
$("#tableWidgetTabulator").tabulator('deselectRow', indexesToDeselect);
},
errorCallback: function (jqXHR, textStatus, errorThrown)
{
@@ -595,5 +738,47 @@ var approveAnrechnung = {
break;
}
},
getSumLvEctsByPreStudent(data){
var result = [];
// Berechne für jeden Prestudenten die kumulierte Summe aller selektierten LV ECTS
data.reduce((prev, curr) => {
if (!prev[curr.prestudent_id])
{
prev[curr.prestudent_id] = {
prestudent_id: curr.prestudent_id,
ectsSumAnzurechnendeLvsSchulisch: 0,
ectsSumAnzurechnendeLvsBeruflich: 0
};
result.push(prev[curr.prestudent_id])
}
// Kumulierte Summe aller selektierten LVs, die angerechnet werden sollen, getrennt nach
// schulischer und beruflicher Qualifikation.
// Ausgenommen ist die universitäre Qualifikation (5), da diese unbegrenzt möglich sind.
if (curr.begruendung_id != 5)
{
if (curr.begruendung_id == 4)
{
prev[curr.prestudent_id].ectsSumAnzurechnendeLvsBeruflich += curr.ects;
}
else
{
prev[curr.prestudent_id].ectsSumAnzurechnendeLvsSchulisch += curr.ects;
}
}
return prev;
}, {});
return result;
},
showNumberSelectedRows(rows){
$('#number-selected').html("Ausgewählte Zeilen: <strong>" + rows.length + "</strong>");
}
}
}
@@ -2,6 +2,8 @@ const ANRECHNUNGSTATUS_APPROVED = 'approved';
const ANRECHNUNGSTATUS_REJECTED = 'rejected';
const HERKUNFT_DER_KENNTNISSE_MAX_LENGTH = 125;
const COLOR_DANGER = '#f2dede';
$(function(){
const uploadMaxFilesize = $('#requestAnrechnung-uploadfile').data('maxsize') ; // in byte
@@ -17,12 +19,67 @@ $(function(){
// Init tooltips
requestAnrechnung.initTooltips();
// Alert message, if maximum ECTS exceeded
requestAnrechnung.alertIfMaxEctsExceeded();
// Alert message inside Begruendungsbox, if maximum ECTS exceeded
requestAnrechnung.alertIfMaxEctsExceededInsideBegruendungsbox();
// Set chars counter for textarea 'Herkunft der Kenntnisse'
requestAnrechnung.setCharsCounter();
// If Sperregrund exists: display Sperre panel, hide Status panel and disable all form elements
requestAnrechnung.displaySperreIfHasSperregrund();
$('#requestAnrechnung-form :input[name="begruendung"]').click(function(e){
var ectsLv = parseFloat($('#ects').text());
var sumEctsSchulisch = parseFloat($('#sumEctsSchulisch').text());
var sumEctsBeruflich = parseFloat($('#sumEctsBeruflich').text());
var begruendung_id = $(this).val();
if ($(this).is(':checked'))
{
$('#sumEctsMsg').remove();
// If Begründung is 'Hochschulzeugnis', return. They are accepted without limit.
if (begruendung_id == 5)
{
return;
}
// If max ECTS is ecceeded
if (begruendung_id == 4)
{
if ((sumEctsSchulisch + sumEctsBeruflich + ectsLv) > 90 ||
(sumEctsBeruflich + ectsLv) > 60
)
{
// Get ECTS Überschreitungs-message for berufliche Qualifikation
var msgBeiEctsUeberschreitung = requestAnrechnung.getMsgBeiEctsUeberschreitung(begruendung_id, ectsLv, sumEctsSchulisch, sumEctsBeruflich);
// Add to Checkbox text
$(this).closest('label').append(msgBeiEctsUeberschreitung);
}
return;
}
else
{
if ((sumEctsSchulisch + sumEctsBeruflich + ectsLv) > 90 ||
(sumEctsSchulisch + ectsLv) > 60
)
{
// Get ECTS Überschreitungs-message for schulische Qualifikation
var msgBeiEctsUeberschreitung = requestAnrechnung.getMsgBeiEctsUeberschreitung(begruendung_id, ectsLv, sumEctsSchulisch, sumEctsBeruflich);
// Add to Checkbox text
$(this).closest('label').append(msgBeiEctsUeberschreitung);
}
}
}
})
$('#requestAnrechnung-form').submit(function(e){
// Avoid form redirecting automatically
@@ -183,5 +240,102 @@ var requestAnrechnung = {
return true;
}
},
sumUpEcts: function(begruendung_id, ects, sumEctsSchulisch, sumEctsBeruflich){
if (begruendung_id == 5)
{
return;
}
if (begruendung_id == 4)
{
$('#sumEctsBeruflich').text(parseFloat(sumEctsBeruflich) + parseFloat(ects));
}
else
{
$('#sumEctsSchulisch').text(parseFloat(sumEctsSchulisch) + parseFloat(ects));
}
$('#sumEctsTotal').text(parseFloat(sumEctsSchulisch) + parseFloat(sumEctsBeruflich) + parseFloat(ects));
},
alertIfMaxEctsExceeded: function(){
if(
(parseFloat($('#sumEctsSchulisch').text())) > 60 ||
(parseFloat($('#sumEctsBeruflich').text())) > 60 ||
(parseFloat($('#sumEctsSchulisch').text()) + parseFloat($('#sumEctsBeruflich').text())) > 90
)
{
$('#requestAnrechnung-maxEctsUeberschrittenMsg')
.html("<br><b>Die Höchstgrenze für Anrechnungen gem. § 12 Abs. 3 Fachhochschulgesetz ist überschritten. </b><i class=\"fa fa-lg fa-info-circle\"></i></br>")
.addClass('bg-danger text-danger')
.tooltip({
title: FHC_PhrasesLib.t("anrechnung", "anrechnungEctsTooltipTextBeiUeberschreitung"),
placement: 'right',
html: true
});
}
},
alertIfMaxEctsExceededInsideBegruendungsbox: function(){
let status_kurzbz = $('#requestAnrechnung-status_kurzbz').data('status_kurzbz');
if (status_kurzbz != ' ' && status_kurzbz != ANRECHNUNGSTATUS_APPROVED)
{
var ectsLv = parseFloat($('#ects').text());
var sumEctsSchulisch = parseFloat($('#sumEctsSchulisch').text());
var sumEctsBeruflich = parseFloat($('#sumEctsBeruflich').text());
var begruendung_id = $('#requestAnrechnung-form :input[name="begruendung"]:checked').val();
// If Begründung is 'Hochschulzeugnis', return. They are accepted without limit.
if (begruendung_id == 5)
{
return;
}
// If max ECTS is ecceeded
if (begruendung_id == 4)
{
if ((sumEctsSchulisch + sumEctsBeruflich + ectsLv) > 90 ||
(sumEctsBeruflich + ectsLv) > 60
)
{
// Get ECTS Überschreitungs-message, depending on schulische or berufliche Qualifikation
var msgBeiEctsUeberschreitung = requestAnrechnung.getMsgBeiEctsUeberschreitung(begruendung_id, ectsLv, sumEctsSchulisch, sumEctsBeruflich);
// Add to Checkbox text
$('#requestAnrechnung-form :input[name="begruendung"]:checked').closest('label').append(msgBeiEctsUeberschreitung);
}
}
else
{
if ((sumEctsSchulisch + sumEctsBeruflich + ectsLv) > 90 ||
(sumEctsSchulisch + ectsLv) > 60
)
{
// Get ECTS Überschreitungs-message, depending on schulische or berufliche Qualifikation
var msgBeiEctsUeberschreitung = requestAnrechnung.getMsgBeiEctsUeberschreitung(begruendung_id, ectsLv, sumEctsSchulisch, sumEctsBeruflich);
// Add to Checkbox text
$('#requestAnrechnung-form :input[name="begruendung"]:checked').closest('label').append(msgBeiEctsUeberschreitung);
}
}
}
},
getMsgBeiEctsUeberschreitung: function(begruendung_id, ects, sumEctsSchulisch, sumEctsBeruflich){
return $('<span id="sumEctsMsg"></span>')
.html(FHC_PhrasesLib.t("anrechnung", "anrechnungEctsTextBeiUeberschreitung",
begruendung_id == 4
? [(sumEctsSchulisch + sumEctsBeruflich + ects), sumEctsSchulisch, (sumEctsBeruflich + ects)] // beruflich
: [(sumEctsSchulisch + sumEctsBeruflich + ects), (sumEctsSchulisch + ects), sumEctsBeruflich])) // schulisch
.append('<i class="fa fa-lg fa-info-circle"></i>')
.addClass('bg-danger text-danger')
.tooltip({
title: FHC_PhrasesLib.t("anrechnung", "anrechnungEctsTooltipTextBeiUeberschreitung"),
placement: 'right',
html: true
});
}
}
@@ -1,4 +1,6 @@
const BASE_URL = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
const CALLED_PATH = FHC_JS_DATA_STORAGE_OBJECT.called_path;
const CONTROLLER_URL = BASE_URL + '/' + CALLED_PATH;
const APPROVE_ANRECHNUNG_DETAIL_URI = "lehre/anrechnung/ReviewAnrechnungDetail";
const ANRECHNUNGSTATUS_PROGRESSED_BY_STGL = 'inProgressDP';
@@ -65,7 +67,7 @@ function func_tableBuilt(table) {
},
target:"_blank"
}
}, false, "status" // place column after status
}, true // place column on the very left
);
}
@@ -121,17 +123,30 @@ var format_empfehlung_anrechnung = function(cell, formatterParams){
: FHC_PhrasesLib.t("ui", "nein");
}
/**
* Returns formatter params for field dokument_bezeichnung (= Spalte Nachweisdokumente)
* NOTE: Returning a formatter param object fixes the problem, that tabulator did not know the url after refreshing the page.
*/
function paramLookup_dokBez(cell){
return {
labelField: 'dokument_bezeichnung',
url: CONTROLLER_URL + '/download?dms_id=' + cell.getData().dms_id,
target: '_blank'
}
}
/*
* Hook to overwrite TableWigdgets select-all-button behaviour
* Select all (filtered) rows that are progressed by stg leiter.
* (Ignore rows that are approved, rejected or in request for recommendation)
*/
function tableWidgetHook_selectAllButton(tableWidgetDiv){
tableWidgetDiv.find("#tableWidgetTabulator").tabulator('getRows', true)
var resultRows = tableWidgetDiv.find("#tableWidgetTabulator").tabulator('getRows', true)
.filter(row =>
row.getData().status_kurzbz == ANRECHNUNGSTATUS_PROGRESSED_BY_LEKTOR
)
.forEach((row => row.select()));
);
tableWidgetDiv.find("#tableWidgetTabulator").tabulator('selectRow', resultRows);
}
@@ -429,4 +444,4 @@ var reviewAnrechnung = {
// Copy begruendung into textarea
textarea.val($.trim($(elem).parent().text()));
}
}
}
@@ -274,12 +274,13 @@ function func_renderComplete(table){
* Select all (filtered) rows and ignore rows that are bestellt and erteilt
*/
function tableWidgetHook_selectAllButton(tableWidgetDiv){
tableWidgetDiv.find("#tableWidgetTabulator").tabulator('getRows', true)
var resultRows = tableWidgetDiv.find("#tableWidgetTabulator").tabulator('getRows', true)
.filter(row => row.getData().bestellt != null && // bestellt
row.getData().erteilt != null && // AND erteilt
row.getData().akzeptiert == null && // AND NOT akzeptiert
row.getData().status != 'Geändert') // AND NOT geändert
.forEach((row => row.select()));
row.getData().status != 'Geändert'); // AND NOT geändert
tableWidgetDiv.find("#tableWidgetTabulator").tabulator('selectRow', resultRows);
}
// -----------------------------------------------------------------------------------------------------------------
@@ -319,12 +319,13 @@ function func_rowUpdated(row){
* Select all (filtered) rows that are bestellt
*/
function tableWidgetHook_selectAllButton(tableWidgetDiv){
tableWidgetDiv.find("#tableWidgetTabulator").tabulator('getRows', true)
var resultRows = tableWidgetDiv.find("#tableWidgetTabulator").tabulator('getRows', true)
.filter(row => row.getData().personalnummer >= 0 && // NOT dummies
row.getData().bestellt != null && // AND bestellt
row.getData().erteilt == null && // AND NOT erteilt
row.getData().status != 'Geändert') // AND NOT geaendert
.forEach((row => row.select()));
row.getData().status != 'Geändert'); // AND NOT geaendert
tableWidgetDiv.find("#tableWidgetTabulator").tabulator('selectRow', resultRows);
}
// -----------------------------------------------------------------------------------------------------------------
@@ -343,7 +343,7 @@ function func_rowUpdated(row){
* Select all (filtered) rows and ignore rows which have status bestellt
*/
function tableWidgetHook_selectAllButton(tableWidgetDiv){
tableWidgetDiv.find("#tableWidgetTabulator").tabulator('getRows', true)
var resultRows = tableWidgetDiv.find("#tableWidgetTabulator").tabulator('getRows', true)
.filter(row => (
row.getData().personalnummer > 0 || // not dummies
row.getData().personalnummer == null) && // include Projektbetreuer
@@ -355,8 +355,9 @@ function tableWidgetHook_selectAllButton(tableWidgetDiv){
(row.getData().bestellt != null && // OR (bestellt
row.getData().status == 'Geändert') // AND geaendert)
)
)
.forEach((row => row.select()));
);
tableWidgetDiv.find("#tableWidgetTabulator").tabulator('selectRow', resultRows);
}
// -----------------------------------------------------------------------------------------------------------------
+176
View File
@@ -0,0 +1,176 @@
$(function(){
var studiensemesterStart = $("#studsemStart").val();
Zverfueg.initDatepicker(studiensemesterStart);
$('#form-zeitverfuegbarkeit').submit(function(e){
e.preventDefault();
let zeitsperre_id = this.zeitsperre_id.value;
let mitarbeiter_uid = this.mitarbeiter_uid.value;
let lektor = this.mitarbeiter_uid.options[this.mitarbeiter_uid.selectedIndex].text;
let bezeichnung = this.bezeichnung.value;
let vondatum = this.vondatum.value;
let vonstunde = this.vonstunde.value;
let bisdatum = this.bisdatum.value;
let bisstunde = this.bisstunde.value;
FHC_AjaxClient.ajaxCallPost(
FHC_JS_DATA_STORAGE_OBJECT.called_path + "/saveZeitverfuegbarkeit",
{
zeitsperre_id: zeitsperre_id,
mitarbeiter_uid: mitarbeiter_uid,
bezeichnung: bezeichnung,
zeitsperretyp_kurzbz: 'ZVerfueg',
vondatum: vondatum,
vonstunde: vonstunde,
bisdatum: bisdatum,
bisstunde: bisstunde
},
{
successCallback: function (data, textStatus, jqXHR)
{
if (FHC_AjaxClient.isError(data))
{
FHC_DialogLib.alertWarning(FHC_AjaxClient.getError(data));
}
if (FHC_AjaxClient.hasData(data))
{
if (zeitsperre_id == '')
{
// Add row
$('#tableWidgetTabulator').tabulator('addRow', {
zeitsperre_id: FHC_AjaxClient.getData(data).zeitsperre_id,
mitarbeiter_uid: mitarbeiter_uid,
lektor: lektor,
vondatum: vondatum,
vonstunde: $.isNumeric(vonstunde) ? vonstunde : '',
bisdatum: bisdatum,
bisstunde: $.isNumeric(bisstunde) ? bisstunde : '',
bezeichnung: bezeichnung
}, true); // true adds new row on top
}
else {
$('#tableWidgetTabulator').tabulator('updateData', [{
zeitsperre_id: zeitsperre_id,
vondatum: vondatum,
vonstunde: $.isNumeric(vonstunde) ? vonstunde : '',
bisdatum: bisdatum,
bisstunde: $.isNumeric(bisstunde) ? bisstunde : '',
bezeichnung: bezeichnung
}]);
}
// Reset form
Zverfueg.resetFormFields();
// Disable form elements
Zverfueg.disableFormElements();
// Display success message
FHC_DialogLib.alertSuccess(FHC_AjaxClient.getData(data).msg);
}
},
errorCallback: function (jqXHR, textStatus, errorThrown)
{
FHC_DialogLib.alertError(FHC_PhrasesLib.t("ui", "systemfehler"));
}
}
);
})
$('#btn-delete').click(function() {
let zeitsperre_id = $('#zeitsperre_id').val();
FHC_AjaxClient.ajaxCallPost(
FHC_JS_DATA_STORAGE_OBJECT.called_path + "/deleteZeitverfuegbarkeit",
{
zeitsperre_id: zeitsperre_id,
},
{
successCallback: function (data, textStatus, jqXHR) {
if (FHC_AjaxClient.isError(data)) {
FHC_DialogLib.alertWarning(FHC_AjaxClient.getError(data));
}
if (FHC_AjaxClient.hasData(data)) {
// Delete row
let row = $('#tableWidgetTabulator').tabulator('getRow', zeitsperre_id);
row.delete(zeitsperre_id);
// Reset form
Zverfueg.resetFormFields();
// Disable form elements
Zverfueg.disableFormElements();
// Display delete message
FHC_DialogLib.alertSuccess(FHC_AjaxClient.getData(data).msg);
}
},
errorCallback: function (jqXHR, textStatus, errorThrown)
{
FHC_DialogLib.alertError(FHC_PhrasesLib.t("ui", "systemfehler"));
}
});
});
$('#btn-break').click(function () {
Zverfueg.disableFormElements();
})
})
var Zverfueg = {
initDatepicker: function (studiensemesterStart) {
// Prevent opening HTMl date picker
$('input[type=date]').on('click', function(event) {
event.preventDefault();
});
$.datepicker.setDefaults($.datepicker.regional['de']);
$( ".zverfueg-datepicker" ).datepicker({
"dateFormat": "yy-mm-dd",
"minDate": $.datepicker.formatDate('yy-mm-dd', new Date(studiensemesterStart))
});
},
resetFormFields: function(){
$('#form-zeitverfuegbarkeit')
.trigger('reset')
.find('input:hidden[name=zeitsperre_id]').val('')
.find('textarea[name=bezeichnung]').val('');
},
disableFormElements: function (){
$('#btn-delete').prop('disabled', true).tooltip('enable');
$('#mitarbeiter_uid').prop('disabled', false);
},
enableFormElements: function (){
$('#btn-delete').prop('disabled', false).tooltip('disable');
$('#mitarbeiter_uid').prop('disabled', true);
}
}
// TABULATOR FUNCTIONS
// ---------------------------------------------------------------------------------------------------------------------
function func_rowSelected(row){
Zverfueg.enableFormElements();
// Set form fields
$('#zeitsperre_id').val(row.getData().zeitsperre_id);
$('#mitarbeiter_uid').val(row.getData().mitarbeiter_uid);
$('#bezeichnung').val(row.getData().bezeichnung);
$('#vondatum').datepicker('setDate', row.getData().vondatum);
$('#bisdatum').datepicker('setDate', row.getData().bisdatum);
$('#vonstunde').val(row.getData().vonstunde);
$('#bisstunde').val(row.getData().bisstunde);
}
function func_rowDeselected(row){
Zverfueg.resetFormFields();
Zverfueg.disableFormElements();
Zverfueg.resetFormFields();
}
+223
View File
@@ -0,0 +1,223 @@
/**
* Javascript file for benutzergruppe management page
*/
var Benutzergruppe = {
getBenutzer: function(gruppe_kurzbz) {
FHC_AjaxClient.ajaxCallGet(
'person/gruppenmanagement/getBenutzer',
{
gruppe_kurzbz: gruppe_kurzbz
},
{
successCallback: function(data, textStatus, jqXHR) {
if (FHC_AjaxClient.isError(data))
{
FHC_DialogLib.alertError(FHC_AjaxClient.getError(data));
return;
}
let benutzerTable = $("#benutzer-table tbody");
benutzerTable.empty();
if (FHC_AjaxClient.hasData(data))
{
// save loaded data
let benutzerData = FHC_AjaxClient.getData(data);
// fill table with Benutzer of Gruppe
for (let i = 0; i < benutzerData.length; i++)
{
let benutzer = benutzerData[i];
benutzerTable.append(
"<tr>"+
"<td>"+benutzer.uid+"</td>"+
"<td>"+benutzer.vorname+"</td>"+
"<td>"+benutzer.nachname+"</td>"+
"<td>"+(benutzer.aktiv === true ? "Ja" : "Nein")+"</td>"+
"<td>"+
"<button class='btn btn-default benutzerLoeschen' id='"+benutzer.uid+"_benutzerLoeschen'>"+
FHC_PhrasesLib.t('ui', 'entfernen')+
"</button>"+
"</td>"+
"</tr>"
);
// add delete event to button
$("#"+benutzer.uid+"_benutzerLoeschen").click(
function() {
Benutzergruppe.removeBenutzer(benutzer.uid, gruppe_kurzbz);
}
)
}
}
// add tablesorter to benutzergruppe table
Benutzergruppe._setTablesorter();
},
errorCallback: function(jqXHR, textStatus, errorThrown) {
FHC_DialogLib.alertError(textStatus);
}
}
);
},
getAllBenutzer: function() {
FHC_AjaxClient.ajaxCallGet(
'person/gruppenmanagement/getAllBenutzer',
null,
{
successCallback: function(data, textStatus, jqXHR) {
if (FHC_AjaxClient.isError(data))
{
FHC_DialogLib.alertError(FHC_AjaxClient.getError(data));
return;
}
if (FHC_AjaxClient.hasData(data))
{
benutzerArr = [];
// save loaded data
let benutzerData = FHC_AjaxClient.getData(data);
for (let i = 0; i < benutzerData.length; i++)
{
let ben = benutzerData[i];
benutzerArr.push(
{
vorname: ben.vorname,
nachname: ben.nachname,
uid: ben.uid,
label: ben.nachname + " " + ben.vorname + " (" + ben.uid + ")",
id: ben.uid
}
);
}
// callback for searching source mitarbeiter array correctly
let sourceCallback = function(request, response)
{
// case insensitive matcher
let matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
// match vorname nachname OR nachname vorname OR uid
response($.grep(benutzerArr, function (value) {
return matcher.test(value.nachname + ' '+value.vorname + ' ' + value.nachname)
|| matcher.test(value.uid);
}));
}
// fill autocomplete field with benutzer data
Benutzergruppe._fillAutocomplete(
'teilnehmerSelect',
'teilnehmer_uid',
sourceCallback
);
}
},
errorCallback: function(jqXHR, textStatus, errorThrown) {
FHC_DialogLib.alertError(textStatus);
}
}
);
},
addBenutzer: function(uid, gruppe_kurzbz) {
FHC_AjaxClient.ajaxCallPost(
'person/gruppenmanagement/addBenutzer',
{
uid: uid,
gruppe_kurzbz: gruppe_kurzbz
},
{
successCallback: function(data, textStatus, jqXHR) {
if (FHC_AjaxClient.isError(data))
{
FHC_DialogLib.alertError(FHC_AjaxClient.getError(data));
return;
}
if (FHC_AjaxClient.hasData(data))
{
// load Benutzer after add to show change
Benutzergruppe.getBenutzer(gruppe_kurzbz);
}
},
errorCallback: function(jqXHR, textStatus, errorThrown) {
FHC_DialogLib.alertError(textStatus);
}
}
);
},
removeBenutzer: function(uid, gruppe_kurzbz) {
FHC_AjaxClient.ajaxCallPost(
'person/gruppenmanagement/removeBenutzer',
{
uid: uid,
gruppe_kurzbz: gruppe_kurzbz
},
{
successCallback: function(data, textStatus, jqXHR) {
if (FHC_AjaxClient.isError(data))
{
FHC_DialogLib.alertError(FHC_AjaxClient.getError(data));
return;
}
if (FHC_AjaxClient.hasData(data))
{
// load Benutzer after remove to show change
Benutzergruppe.getBenutzer(gruppe_kurzbz);
}
},
errorCallback: function(jqXHR, textStatus, errorThrown) {
FHC_DialogLib.alertError(textStatus);
}
}
);
},
_fillAutocomplete: function(autocompleteId, idFieldId, source) {
// jQuery ui autocomplete for benutzer
$("#"+autocompleteId).autocomplete(
{
// custom matcher
source: source,
autoFocus: true,
select: function(event, ui)
{
// when autocmplete entry selected, display label text in autocomplete, fill hidden value field
$("#"+autocompleteId).val(ui.item.label);
$("#"+idFieldId).val(ui.item.id);
return false;
}
}
);
},
_setTablesorter: function() {
Tablesort.addTablesorter(
// sort by first and third column asc, show filters beggining with 2 Benutzer, exclude fifth column from filter
"benutzer-table", [[0,0], [2,0]], ["filter", "zebra"], 2, {headers: {4: {filter: false}}}
)
}
};
/**
* When JQuery is up
*/
$(document).ready(function() {
// get the group name
let gruppe_kurzbz = $("#gruppe_kurzbz").val();
// load Benutzer for autocomplete selection
Benutzergruppe.getAllBenutzer();
// load Benutzer for table
Benutzergruppe.getBenutzer(gruppe_kurzbz);
// add click event to "add Benutzer" button
$("#teilnehmerHinzufuegen").click(function(){
let uid = $("#teilnehmer_uid").val();
Benutzergruppe.addBenutzer(uid, gruppe_kurzbz);
$("#teilnehmerSelect").val('');
}
);
});