mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-25 08:34:29 +00:00
Merge branch 'master' into feature-13011/installation_on_multiple_servers
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@@ -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');
|
||||
@@ -0,0 +1,5 @@
|
||||
import Search from "./search.js";
|
||||
|
||||
export default {
|
||||
"Search": Search
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
Vendored
+3
-1
@@ -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');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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>
|
||||
`
|
||||
};
|
||||
|
||||
@@ -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
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
 X 
|
||||
</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>
|
||||
 X 
|
||||
</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>
|
||||
`
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
  {{ 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>
|
||||
`
|
||||
};
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -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: {
|
||||
}
|
||||
};
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -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"]);
|
||||
|
||||
@@ -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'> 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(" <span id='zgvUebernehmenNotice' class='text-warning'>keine ZGV vorhanden</span>");
|
||||
btn.after("<span id='zgvUebernehmenNotice' class='text-warning'> 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;
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
)
|
||||
});
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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('');
|
||||
}
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user