Compare commits

...
Author SHA1 Message Date
ma0068 5cd0897348 Rename route and Path from Zeitsperren to Zeitsperrenma 2026-08-17 16:16:08 +02:00
ma0068 0d5c898106 add routes for types all, fix, lector, oe, stg and ass
remove component from vertragsverwaltung
 refactor component Zeitsperrenmitarbeiter_uid
 phrase
 view change table back from dark mode
 add validations for params
2026-08-06 11:42:36 +02:00
ma0068 0a46bf52dd - neue funktion loadZeitsperrenforUid
– route für maUid
- Zeitsperren als Cis-App
– link für Zeitsperren maUid in Mitarbeiterprofil
- component ZeitsperrenMitarbeiterUid
- Dropdown oes:show only active Oes
2026-08-04 08:00:40 +02:00
ma0068 1afc4c9a29 add link to substitution 2026-07-30 16:39:25 +02:00
ma0068 96b4210d21 refactor backend
css file for showing inactive items in dropdown
fix missing view for vertretung zeitsperren
sticky top for header
2026-07-30 15:29:15 +02:00
ma0068 85fcecdcf6 add type all to validator 2026-07-30 11:24:25 +02:00
ma0068 55dc2b26d2 refactor listsZeitsperren
add phrases
remove logs
add watcher for type
show table in view lectorStg and byOe only if selectedValue exists
2026-07-30 11:01:23 +02:00
ma0068 9c7a85826b refactor ZeitsperrenMa, rename aktuelleZeitsperren, add Phrases to ZeitsperrenMa 2026-07-29 17:52:23 +02:00
ma0068 e876b9e4ab Zeitsperren Mitarbeiter - add component to Vertragsverwaltung 2026-07-24 13:11:40 +02:00
16 changed files with 1507 additions and 5 deletions
+5
View File
@@ -68,6 +68,11 @@ $route['Cis/OtherLvPlan/.*'] = 'Cis/OtherLvPlan/index/$1';
//Route for LV Plan Stg/Semester/Verband/Gruppe
$route['Cis/StgOrgLvPlan/.*'] = 'Cis/StgOrgLvPlan/index/$1';
//Route for Zeitsperrenma
$route['Cis/Zeitsperrenma/.*'] = 'Cis/Zeitsperrenma/index/$1';
//Route für Zeitsperren
//$route['Cis/Zeitsperren/.*'] = 'Cis/Zeitsperren/index/$1';
$route['Abgabetool/Assistenz'] = 'Cis/Abgabetool/Assistenz';
$route['Abgabetool/Assistenz/(:any)'] = 'Cis/Abgabetool/Assistenz/$1';
$route['Abgabetool/Mitarbeiter'] = 'Cis/Abgabetool/Mitarbeiter';
@@ -0,0 +1,31 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
*
*/
class Zeitsperrenma extends Auth_Controller
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct([
'index' => ['basis/cis:r']
]);
}
// -----------------------------------------------------------------------------------------------------------------
// Public methods
/**
* @return void
*/
public function index()
{
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'Zeitsperrenma']);
}
}
@@ -0,0 +1,167 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class MaZeitsperren extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'getAllActiveZeitsperren' => self::PERM_LOGGED,
'getAllZeitsperrenFixeMa' => self::PERM_LOGGED,
'getAllZeitsperrenLector' => self::PERM_LOGGED,
'getAllZeitsperrenOes' => self::PERM_LOGGED,
'getZeitsperrenAss' => self::PERM_LOGGED,
'getStgLectors' => self::PERM_LOGGED,
'loadZeitsperrenLectorStg' => self::PERM_LOGGED,
'loadZeitsperrenMa' => self::PERM_LOGGED,
'getDetailsMa' => self::PERM_LOGGED,
]);
// Load Libraries
$this->load->library('VariableLib', ['uid' => getAuthUID()]);
$this->load->library('form_validation');
// Load language phrases
$this->loadPhrases([
'ui',
'person',
'zeitsperren'
]);
// Load models
$this->load->model('ressource/Zeitsperre_model', 'ZeitsperreModel');
}
//only user with zeitsperren
public function getAllActiveZeitsperren($days)
{
$result = $this->ZeitsperreModel->getZeitsperrenForNextDays($days);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
//TODO: check query: more results after join with hr-table
//all fixe Ma
public function getAllZeitsperrenFixeMa($days)
{
$von = date('Y-m-d');
$bis = date('Y-m-d', strtotime("+{$days} days"));
$result = $this->ZeitsperreModel->getMitarbeiterWithZeitsperren($von, $bis, true, false, null, false);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
public function getAllZeitsperrenLector($days)
{
$von = date('Y-m-d');
$bis = date('Y-m-d', strtotime("+{$days} days"));
$result = $this->ZeitsperreModel->getMitarbeiterWithZeitsperren($von, $bis, false, true, null, false);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
public function getZeitsperrenAss($days)
{
$von = date('Y-m-d');
$bis = date('Y-m-d', strtotime("+{$days} days"));
$result = $this->ZeitsperreModel->getMitarbeiterWithZeitsperren($von, $bis, false, false, null, true);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
public function getAllZeitsperrenOes($days, $oe)
{
if(!$oe)
{
return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'OE Kurzbezeichnung']), self::ERROR_TYPE_GENERAL);
}
$von = date('Y-m-d');
$bis = date('Y-m-d', strtotime("+{$days} days"));
$result = $this->ZeitsperreModel->getMitarbeiterWithZeitsperren($von, $bis, false, false, $oe, false);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
public function loadZeitsperrenLectorStg($days, $stg)
{
if(!$stg)
{
return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Studiengangskennzahl']), self::ERROR_TYPE_GENERAL);
}
if(!is_numeric($stg))
{
return $this->terminateWithError($this->p->t('ui', 'error_paramNoNumber', ['param'=> 'Studiengangskennzahl']), self::ERROR_TYPE_GENERAL);
}
$von = date('Y-m-d');
$bis = date('Y-m-d', strtotime("+{$days} days"));
$result = $this->ZeitsperreModel->getMitarbeiterWithZeitsperren($von, $bis, false, true, false, false, $stg);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
public function getStgLectors()
{
$sql = "
select
studiengang_kz,
kurzbz,
kurzbzlang,
typ,
bezeichnung,
kurzbzlang || ' (' || bezeichnung || ')' AS label,
aktiv
from
public.tbl_studiengang
where
typ in ('b','m')
order by typ asc, kurzbz Asc
";
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
$result = $this->StudiengangModel->execReadOnlyQuery($sql);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
public function loadZeitsperrenMa($days, $uid)
{
if ($uid === null || $uid === '')
{
return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Mitarbeiter UID']), self::ERROR_TYPE_GENERAL);
}
$result = $this->ZeitsperreModel->getZeitsperrenForNextDays($days, $uid);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
public function getDetailsMa($uid)
{
if ($uid === null || $uid === '')
{
$this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Mitarbeiter UID']), self::ERROR_TYPE_GENERAL);
}
$this->load->model('ressource/Person_model', 'PersonModel');
$result = $this->PersonModel->getFullName($uid);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
}
@@ -61,4 +61,145 @@ class Zeitsperre_model extends DB_Model
return $this->execQuery($qry);
}
/**
* getZeitsperren of Mitarbeiter for the next days
* @ days: count of the intervall of the next days
* @return array
*/
public function getZeitsperrenForNextDays($days, $uid=null)
{
$von = date('Y-m-d');
$bis = date('Y-m-d', strtotime("+{$days} days"));
$paramsArray = [$von, $bis, $bis, $von];
if($uid)
$paramsArray[] = $uid;
$qry = "select
nachname,
vorname,
uid,
vondatum,
bisdatum,
vertretung_uid,
erreichbarkeit_kurzbz,
mv.kurzbz
from
campus.vw_mitarbeiter
join campus.tbl_zeitsperre on
(uid = mitarbeiter_uid)
left join public.tbl_mitarbeiter mv on campus.tbl_zeitsperre.vertretung_uid = mv.mitarbeiter_uid
where
((? <= bisdatum
and ? >= bisdatum)
or (?>= vondatum
and ? <= vondatum))";
if($uid)
$qry .= " and uid = ? ";
$qry .= "
order by nachname
";
$result = $this->execQuery($qry, $paramsArray);
return $result;
}
public function getMitarbeiterWithZeitsperren($von, $bis, $fix=false, $lector=false, $oe=null, $ass=false, $stg=false)
{
$paramsArray = [$von, $bis, $bis, $von];
if($oe)
{
$paramsArray[] = $oe;
}
if($stg)
{
$paramsArray[] = $stg;
}
$qry = "
SELECT
m.nachname,
m.vorname,
m.uid,
z.vondatum,
z.bisdatum,
z.vertretung_uid,
z.erreichbarkeit_kurzbz,
m.lektor,
m.fixangestellt,
mv.kurzbz
FROM campus.vw_mitarbeiter m
join public.tbl_benutzer bn on bn.uid = m.uid";
if($oe || $ass || $stg)
{
$qry .= " JOIN public.tbl_benutzerfunktion bf on bf.uid = bn.uid";
}
if($stg)
{
$qry .= " JOIN public.tbl_studiengang stg using (oe_kurzbz)";
}
$qry.= "
LEFT JOIN campus.tbl_zeitsperre z
ON m.uid = z.mitarbeiter_uid
AND (
(? <= z.bisdatum AND ? >= z.bisdatum)
OR
(? >= z.vondatum AND ? <= z.vondatum)
)
left join public.tbl_mitarbeiter mv on z.vertretung_uid = mv.mitarbeiter_uid
where bn.aktiv = true
";
if($fix) {
$qry.= " AND m.fixangestellt = true";
}
if($lector) {
$qry.= " AND m.lektor = true";
}
if ($oe)
{
$qry.= "
AND bf.funktion_kurzbz ='oezuordnung'
AND bf.oe_kurzbz= ?
AND (bf.datum_von is null or bf.datum_von <=now())
AND (bf.datum_bis is null or bf.datum_bis >= now())
";
}
if ($ass)
{
$qry.= "
AND bf.funktion_kurzbz ='ass'
AND (bf.datum_von is null or bf.datum_von <=now())
AND (bf.datum_bis is null or bf.datum_bis >= now())
";
}
if ($stg)
{
$qry.= "
AND stg.studiengang_kz = ?
";
}
$qry .= " order by nachname, vorname, uid";
$result = $this->execQuery($qry, $paramsArray);
return $result;
}
}
@@ -23,7 +23,8 @@ $includesArray = array(
'public/css/components/FormUnderline.css',
'public/css/components/abgabetool/abgabe.css',
'public/css/Cis4/Cms.css',
'public/css/Cis4/Studium.css'
'public/css/Cis4/Studium.css',
'public/css/components/Zeitsperren.css',
),
'customJSs' => array(
'vendor/npm-asset/primevue/accordion/accordion.min.js',
+3 -2
View File
@@ -12,13 +12,14 @@ $includesArray = array(
'tinymce5' => true,
'phrases' => array(
'global',
'ui',
'ui'
),
'customCSSs' => [
'public/css/components/vue-datepicker.css',
'public/css/components/primevue.css',
'public/css/Vertragsverwaltung.css',
'public/css/components/Detailheader.css'
'public/css/components/Detailheader.css',
'public/css/components/Zeitsperren.css'
],
'customJSs' => [
#'vendor/npm-asset/primevue/tree/tree.min.js',
+3
View File
@@ -0,0 +1,3 @@
.item-inactive {
text-decoration: line-through;
}
+78
View File
@@ -0,0 +1,78 @@
/**
* Copyright (C) 2026 fhcomplete.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
export default {
loadAllActiveZeitsperren(days) {
return {
method: 'get',
url:'api/frontend/v1/MaZeitsperren/getAllActiveZeitsperren/' + days
};
},
loadAllZeitsperrenFixeMa(days) {
return {
method: 'get',
url:'api/frontend/v1/MaZeitsperren/getAllZeitsperrenFixeMa/' + days
};
},
loadAllZeitsperrenLector(days) {
return {
method: 'get',
url:'api/frontend/v1/MaZeitsperren/getAllZeitsperrenLector/' + days
};
},
getAllOes(){
return {
method: 'get',
url:'api/frontend/v1/funktionen/Funktionen/getAllOrgUnits'
};
},
loadAllZeitsperrenOE(days, oe) {
return {
method: 'get',
url:'api/frontend/v1/MaZeitsperren/getAllZeitsperrenOes/' + days + '/' + oe,
};
},
loadZeitsperrenAss(days) {
return {
method: 'get',
url:'api/frontend/v1/MaZeitsperren/getZeitsperrenAss/' + days
};
},
getAllStg(){
return {
method: 'get',
url:'api/frontend/v1/MaZeitsperren/getStgLectors'
};
},
loadZeitsperrenLectorStg(days,stg) {
return {
method: 'get',
url:'api/frontend/v1/MaZeitsperren/loadZeitsperrenLectorStg/' + days + '/' + stg,
};
},
loadZeitsperrenMa(days, uid) {
return {
method: 'get',
url:'api/frontend/v1/MaZeitsperren/loadZeitsperrenMa/' + days + '/' + uid,
};
},
getDetailsMa(uid){
return {
method: 'get',
url:'api/frontend/v1/MaZeitsperren/getDetailsMa/' + uid,
};
}
}
+12
View File
@@ -19,6 +19,7 @@ import DeadlineOverview from "../../components/Cis/Abgabetool/DeadlineOverview.j
import Studium from "../../components/Cis/Studium/Studium.js";
import StgOrgLvPlan from "../../components/Cis/LvPlan/StgOrg.js";
import OtherLvPlan from "../../components/Cis/LvPlan/OtherLvPlan.js";
import ZeitsperrenMa from "../../components/Cis/ZeitsperrenMitarbeiter/ZeitsperrenMa.js";
import ApiRouteInfo from '../../api/factory/routeinfo.js';
import {capitalize} from "../../helpers/StringHelpers.js";
@@ -231,6 +232,17 @@ const router = VueRouter.createRouter({
component: FhcDashboard,
props: {dashboard: 'CIS'},
},
{
path: '/Cis/Zeitsperrenma/:type(all|fix|lector|ma|oe|stg|ass)?/:id?/:days?',
name: 'ZeitsperrenMa',
component: ZeitsperrenMa,
props: route => {
//console.log('ROUTE PARAMS', route.params);
return {
propsViewData: route.params
};
}
},
{
path: '/:pathMatch(.*)*',
name: 'Fallback',
@@ -4,6 +4,7 @@ import RoleInformation from "./ProfilComponents/RoleInformation.js";
import ProfilEmails from "./ProfilComponents/ProfilEmails.js";
import ProfilInformation from "./ProfilComponents/ProfilInformation.js";
import QuickLinks from "./ProfilComponents/QuickLinks.js";
import ZeitsperrenUid from "../../Cis/ZeitsperrenMitarbeiter/Details/ZeitsperrenMitarbeiteruid.js";
import { dateFilter } from "../../../tabulator/filters/Dates.js";
@@ -15,6 +16,7 @@ export default {
ProfilEmails,
ProfilInformation,
QuickLinks,
ZeitsperrenUid
},
inject: ["collapseFunction", "language"],
data() {
@@ -210,8 +212,10 @@ export default {
}
return quickLinks;
},
stringTimelocks(){
return `${this.$p.t("zeitsperren", "zeitsperrenVon")} ` + this.data.vorname + " " + this.data.nachname;
}
},
template: /*html*/ `
<div class="container-fluid text-break fhc-form" >
@@ -279,6 +283,16 @@ export default {
<quick-links :title="$p.t('profil/quickLinks')" :links="quickLinks" />
</div>
</div>
<!-- LINKS MITARBEITER -->
<div class="card mb-2">
<div class= "card-body">
<zeitsperren-uid
:maUid="data.username"
:days="14"
:title="stringTimelocks"
></zeitsperren-uid>
</div>
</div>
<!-- MAILVERTEILER -->
<div class="row">
<div class="col">
@@ -0,0 +1,34 @@
export default {
name: "timelocksMitarbeiteruid",
props: {
maUid: {
type: String
},
days: {
type: Number
},
title: {
type: String
}
},
methods: {
link(maUid, days){
this.$router.push({
name: 'ZeitsperrenMa',
params: {
type: 'ma',
id: maUid,
days: days
}
});
}
},
template: `
<div>
<a href="#" @click.prevent="link(maUid, days)">
{{title}}
</a>
</div>
`,
}
@@ -0,0 +1,577 @@
import {CoreFilterCmpt} from "../../../filter/Filter.js";
import ApiMaTimelocks from "../../../../api/factory/zeitsperren.js";
import FormForm from "../../../Form/Form.js";
import FormInput from "../../../Form/Input.js";
import PvAutoComplete from "../../../../../../index.ci.php/public/js/components/primevue/autocomplete/autocomplete.esm.min.js";
export default {
name: "listsTimelocks",
components: {
FormForm,
FormInput,
PvAutoComplete,
CoreFilterCmpt
},
props: {
type: {
type: String,
default: 'all',
validator(value) {
return [
'all',
'fix',
'lector',
'oe',
'ass',
'stg',
'ma'
].includes(value)
}
},
tage: {
type: String
},
id: {
type: String
},
},
data(){
return {
interval: 14,
days: {},
arrayMaTimelocks: [],
listOes: [],
filteredOes: [],
selectedOe: null,
oe_kurzbz: null,
listStg: [],
filteredStg: [],
selectedStg: null,
studiengang_kz: null,
showTable: true,
fullName: null,
maUid: null,
validStgs: [],
validOes: []
}
},
methods: {
loadAllActiveZeitsperren(days){
this.$api
.call(ApiMaTimelocks.loadAllActiveZeitsperren(days))
.then(result => {
this.arrayMaTimelocks = result.data;
})
},
loadZeitsperrenFixeMa(days){
this.$api
.call(ApiMaTimelocks.loadAllZeitsperrenFixeMa(days))
.then(result => {
this.arrayMaTimelocks = result.data;
})
},
loadZeitsperrenLector(days){
this.$api
.call(ApiMaTimelocks.loadAllZeitsperrenLector(days))
.then(result => {
this.arrayMaTimelocks = result.data;
})
},
loadZeitsperrenOE(days, oe){
this.$router.push({
name: 'ZeitsperrenMa',
params: {
type: this.$route.params.type,
id: oe,
days: days
}
});
this.$api
.call(ApiMaTimelocks.loadAllZeitsperrenOE(days, oe))
.then(result => {
this.arrayMaTimelocks = result.data;
})
},
loadZeitsperrenAss(days){
this.$api
.call(ApiMaTimelocks.loadZeitsperrenAss(days))
.then(result => {
this.arrayMaTimelocks = result.data;
})
},
loadZeitsperrenStg(days, stg){
this.$router.push({
name: 'ZeitsperrenMa',
params: {
type: this.$route.params.type,
id: stg,
days: days
}
});
this.$api
.call(ApiMaTimelocks.loadZeitsperrenLectorStg(days, stg))
.then(result => {
this.arrayMaTimelocks = result.data;
})
},
loadZeitsperrenMa(days, uid){
this.$api
.call(ApiMaTimelocks.loadZeitsperrenMa(days, uid))
.then(result => {
this.arrayMaTimelocks = result.data;
})
},
createDays(countDays) {
const today = new Date();
//get Monday before today
const mondayBeforeToday = new Date(today);
const day = today.getDay();
const diff = day === 0 ? 6 : day - 1;
mondayBeforeToday.setDate(today.getDate() - diff);
this.days = Array.from({ length: countDays + 1 }, (_, i) => {
const date = new Date(mondayBeforeToday);
date.setDate(mondayBeforeToday.getDate() + i);
return {
date: date.toISOString().substring(0, 10), // 2026-07-13
weekday: date.toLocaleDateString('de-AT', { weekday: 'short' }),
day: date.toLocaleDateString('de-AT', {
day: '2-digit',
month: '2-digit'
})
};
});
},
createArrayMa(type){
this.showTable = true;
if(type == "fix") {
if(this.id && this.isZifferString(this.id))
this.interval = Number(this.id) < 100 ? Number(this.id) : this.interval;
this.loadZeitsperrenFixeMa(this.interval);
}
else if(type == "lector") {
if(this.id && this.isZifferString(this.id))
this.interval = Number(this.id) < 100 ? Number(this.id) : this.interval;
this.loadZeitsperrenLector(this.interval);
}
else if(type == "oe") {
this.loadOes().then(() => {
if(this.id && this.validOes.includes(this.id)) {
const countDays = this.tage ? Number(this.tage) : this.interval;
this.oe_temp = this.listOes.filter(
item => item.oe_kurzbz === this.id
);
this.selectedOe = this.oe_temp[0];
this.loadZeitsperrenOE(
countDays,
this.selectedOe.oe_kurzbz
);
} else {
if(this.id)
this.interval = Number(this.id) < 100
? Number(this.id)
: this.interval;
this.showTable = false;
this.selectedOe = null;
}
});
}
else if(type == "stg") {
this.loadStgs().then(() => {
if(this.id && this.validStgs.includes(Number(this.id)))
{
const countDays= this.tage ? Number(this.tage) : this.interval;
this.stg_temp = this.listStg.filter(
item => item.studiengang_kz === Number(this.id)
);
this.selectedStg = this.stg_temp[0];
this.loadZeitsperrenStg(countDays, this.id)
}
else
{
if(this.id && this.isZifferString(this.id))
this.interval = Number(this.id) < 100 ? Number(this.id) : this.interval;
this.showTable = false;
this.selectedStg = null;
}
});
}
else if(type == "all") {
if(this.id && this.isZifferString(this.id))
this.interval = Number(this.id) < 100 ? Number(this.id) : this.interval;
this.loadAllActiveZeitsperren(this.interval);
}
else if(type == "ass") {
if(this.id && this.isZifferString(this.id))
this.interval = Number(this.id) < 100 ? Number(this.id) : this.interval;
this.loadZeitsperrenAss(this.interval);
}
else if(type == "ma") {
if(!this.id)
this.$fhcAlert.alertError(this.$p.t('ui', 'error_missingId', {id: "mitarbeiteruid"}));
const countDays= this.tage ? this.tage : this.interval;
this.loadZeitsperrenMa(countDays, this.id);
this.loadDetailsMa(this.id);
}
else
{
//route back if no type found
this.$router.push({
name: 'ZeitsperrenMa',
});
}
},
isBlocked(mitarbeiter, tag) {
if (!mitarbeiter?.sperren) {
return false;
}
return mitarbeiter.sperren.some(s =>
tag >= s.vondatum &&
tag <= s.bisdatum
);
},
getSperre(mitarbeiter, tag){
return mitarbeiter.sperren.find(s =>
tag >= s.vondatum &&
tag <= s.bisdatum
);
},
limitDays(event) {
let value = event.target.value.replace(/\D/g, '').slice(0, 2);
event.target.value = value;
this.interval = value ? Number(value) : null;
},
filterOes(event) {
const query = event.query.toLowerCase();
this.filteredOes = this.listOes.filter(item =>
item.label.toLowerCase().includes(query)
);
},
filterStg(event) {
const query = event.query.toLowerCase();
this.filteredStg = this.listStg.filter(item =>
item.label.toLowerCase().includes(query)
);
},
link(uid) {
return (
FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router +
"/Cis/Profil/View/"+
uid
);
},
loadDetailsMa(uid){
if(!uid)
this.$fhcAlert.alertError(this.$p.t('ui', 'error_fieldNotFound', {field: "UID Mitarbeiter"}));
this.$api
.call(ApiMaTimelocks.getDetailsMa(uid))
.then(result => {
this.fullName = result.data;
})
},
isZifferString(wert) {
//to check if the wert of the route param is a ziffer or a real String
return typeof wert === 'string' && wert.trim() !== '' && !isNaN(wert);
},
async loadOes() {
try {
const result = await this.$api.call(ApiMaTimelocks.getAllOes());
this.listOes = result.data.filter(item => item.aktiv);
this.validOes = this.listOes.map(item => item.oe_kurzbz);
} catch (e) {
this.$fhcAlert.handleSystemError(e);
}
return this.validOes;
},
async loadStgs() {
try {
const result = await this.$api.call(ApiMaTimelocks.getAllStg());
this.listStg = result.data;
this.validStgs = this.listStg.map(item => item.studiengang_kz);
} catch (e) {
this.$fhcAlert.handleSystemError(e);
}
return this.validOes;
},
checkRoute(){
if (this.type === 'ma' && !this.id) {
//const errorString = this.$p.t('ui', 'successSave');
const errorString = "Keine ID für Mitarbeiter übergeben";
return errorString;
}
if (this.type === 'stg' && !this.isZifferString(this.id)) {
//const errorString = this.$p.t('ui', 'successSave');
const errorString = "Studiengangskennzahl darf nur aus Zahlen bestehen";
return errorString;
}
}
},
computed: {
today(){
const today = new Date();
const day = today.toLocaleDateString('de-AT', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
});
return day;
},
mondayBeforeToday(){
const today = new Date();
//get Monday before today
const mondayBeforeToday = new Date(today);
const day = today.getDay();
const diff = day === 0 ? 6 : day - 1;
mondayBeforeToday.setDate(today.getDate() - diff);
return mondayBeforeToday;
},
endInterval(){
const today = new Date();
const end = new Date(this.mondayBeforeToday);
end.setDate(end.getDate() + this.interval);
return end.toLocaleDateString('de-AT', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
});
},
mitarbeiter() {
const map = {};
this.arrayMaTimelocks.forEach(z => {
if (!map[z.uid]) {
map[z.uid] = [];
}
map[z.uid].push(z);
});
return Object.entries(map).map(([mitarbeiter_uid, sperren]) => ({
mitarbeiter_uid,
sperren
}));
},
},
watch: {
interval: {
handler(newVal) {
if (newVal) {
if(this.type == "fix") {
this.loadZeitsperrenFixeMa(newVal);
}
else if(this.type == "lector") {
this.loadZeitsperrenLector(newVal);
}
else if(this.type == "oe") {
if(this.oe_kurzbz && this.oe_kurzbz !="")
this.loadZeitsperrenOE(newVal, this.oe_kurzbz);
}
else if(this.type == "all")
{
this.loadAllActiveZeitsperren(newVal);
}
else if(this.type == "ass") {
this.loadZeitsperrenAss(newVal);
}
else if(this.type == "stg") {
if(this.selectedStg )
this.loadZeitsperrenStg(newVal, this.studiengang_kz);
}
else if(this.type == "ma") {
this.loadZeitsperrenMa(newVal, this.maUid);
}
else
{
this.$fhcAlert.alertError(this.$p.t('ui', 'error_fieldNotFound', {field: "Typ Zeitsperre"}));
}
this.createDays(newVal);
}
},
deep: true,
},
selectedOe(newVal) {
this.oe_kurzbz = newVal?.oe_kurzbz || '';
},
oe_kurzbz(newVal){
{
if(newVal != "") {
this.loadZeitsperrenOE(this.interval, newVal);
this.showTable = true;
}
}
},
selectedStg(newVal) {
this.studiengang_kz = newVal?.studiengang_kz || '';
},
studiengang_kz(newVal){
{
if(newVal != "") {
this.loadZeitsperrenStg(this.interval, newVal);
this.showTable = true;
}
}
},
type(newVal){
{
if(newVal != "")
this.createArrayMa(newVal);
}
},
},
created(){
const error = this.checkRoute();
if (error) {
console.log(error);
this.$fhcAlert.alertError(error);
return;
}
this.createArrayMa(this.type);
if(this.tage && Number(this.tage) < 100) {
this.createDays(Number(this.tage));
this.interval = Number(this.tage);
}
else
this.createDays(this.interval);
if (this.type === 'oe') {
this.oe_kurzbz = this.id
} else if (this.type === 'stg'){
this.studiengang_kz = this.id;
}
},
template: `
<div class="w-100 h-100">
<div class="sticky-top bg-white p-3 border-bottom">
<h4 class="mt-3"><span v-if="type=='all'">{{$p.t('zeitsperren/title_allMa')}}</span>
<span v-if="type=='fix'">{{$p.t('zeitsperren/title_fix')}}</span>
<span v-if="type=='lector'">{{$p.t('zeitsperren/title_fixLecturers')}}</span>
<span v-if="type=='oe'">{{$p.t('zeitsperren/title_byOe')}}</span>
<span v-if="type=='stg'">{{$p.t('zeitsperren/title_lectStg')}}</span>
<span v-if="type=='ass'">{{$p.t('zeitsperren/title_ass')}}</span>
<span v-if="type=='ma'">{{$p.t('zeitsperren/zeitsperrenVon')}} {{fullName}}</span>
{{ mondayBeforeToday.toLocaleDateString('de-AT') }} - {{endInterval}}
</h4>
<div class="d-flex align-items-center gap-2 mb-3">
<label for="days">Anzahl Tage:</label>
<input
id="days"
v-model.number="interval"
type="number"
class="form-control"
style="width: 90px"
min="1"
max="99"
@input="limitDays"
>
<label v-if="type=='oe'">{{$p.t('lehre/organisationseinheit')}}</label>
<div v-if="type=='oe'" class="flex-grow-1">
<form-form class="g-3" ref="oeSelectForm">
<form-input
container-class="w-50"
type="autocomplete"
name="oe_kurzbz"
v-model="selectedOe"
forceSelection
optionLabel="label"
optionValue="oe_kurzbz"
:suggestions="filteredOes"
dropdown
@complete="filterOes"
>
<template #option="slotProps">
<div
:class="!slotProps.option.aktiv
? 'item-inactive'
: ''"
>
{{slotProps.option.label}}
</div>
</template>
</form-input>
</form-form>
</div>
<label v-if="type=='stg'">{{$p.t('zeitsperren/lektor_innen')}}</label>
<div v-if="type=='stg'" class="flex-grow-1">
<form-form class="g-3" ref="oeSelectForm">
<form-input
container-class="w-50"
type="autocomplete"
name="studiengang_kz"
v-model="selectedStg"
forceSelection
optionLabel="label"
optionValue="studiengang_kz"
:suggestions="filteredStg"
dropdown
@complete="filterStg"
>
<template #option="slotProps">
<div
:class="!slotProps.option.aktiv
? 'item-inactive'
: ''"
>
{{slotProps.option.label}}
</div>
</template>
</form-input>
</form-form>
</div>
</div>
</div>
<table v-if="showTable" class="table table-striped table-bordered">
<thead>
<tr>
<th scope="col"> UID </th>
<th v-for="day in days" :key="day.date">
<div>{{ day.weekday }}</div>
<div>{{ day.day }}</div>
</th>
</tr>
</thead>
<tbody>
<tr
v-for="m in mitarbeiter"
:key="m.uid"
>
<td>{{m.sperren[0].nachname}} {{m.sperren[0].vorname}}</td>
<td
v-for="day in days"
:key="day.date"
:class="{ 'table-warning': day.weekday === 'Sa' || day.weekday === 'So' }"
>
<template v-if="sperre = getSperre(m, day.date)">
{{$p.t('zeitsperren/abwesend')}}
<div v-if="sperre.kurzbz">
V: <a :href="link(sperre.vertretung_uid)">
{{ sperre.kurzbz }}
</a>
</div>
<div v-if="sperre.erreichbarkeit_kurzbz">E: {{ sperre.erreichbarkeit_kurzbz }}</div>
</template>
</td>
</tr>
</tbody>
</table>
<div v-if="!arrayMaTimelocks.length">
<p>{{$p.t('ui/keineEintraegeGefunden')}}</p>
</div>
</div>
`,
}
@@ -0,0 +1,95 @@
import listsZeitsperren from './Details/listsZeitsperren.js';
import MitarbeiterZeitsperren from './Details/ZeitsperrenMitarbeiteruid.js';
export const DEFAULT_INTERVAL_DAYS = 14;
export default {
name: 'ZeitsperrenMa',
components: {
listsZeitsperren,
MitarbeiterZeitsperren
},
props: {
propsViewData: Object
},
data(){
return {
activeView: null,
buttons: [
{
key: 'all',
title: 'zeitsperren/btn_all_current',
class: 'btn-primary'
},
{
key: 'fix',
title: 'zeitsperren/btn_all_fix',
class: 'btn-secondary'
},
{
key: 'lector',
title: 'zeitsperren/btn_fix_lect',
class: 'btn-secondary'
},
{
key: 'oe',
title: 'zeitsperren/btn_oes',
class: 'btn-secondary'
},
{
key: 'ass',
title: 'zeitsperren/btn_all_ass',
class: 'btn-secondary'
},
{
key: 'stg',
title: 'zeitsperren/btn_lect_stg',
class: 'btn-secondary'
}
],
}
},
methods: {
show(view) {
this.activeView = this.activeView === view ? null : view;
},
route(view) {
this.activeView = this.activeView === view ? null : view;
this.$router.push({
name: 'ZeitsperrenMa',
params: {
type: this.activeView,
days: DEFAULT_INTERVAL_DAYS
}
});
},
},
template: `
<div class="base-zeitsperrenma w-100 h-100">
<div class="row g-1">
<div
class="col"
v-for="button in buttons"
:key="button.key"
>
<button
class="btn w-100"
:class="button.class"
@click="route(button.key)"
>
{{ $p.t(button.title) }}
</button>
</div>
</div>
<lists-zeitsperren
:type="propsViewData.type"
:id="propsViewData.id"
:tage="propsViewData.days"
/>
</div>
`,
}
@@ -5,7 +5,6 @@ import VertraegeMitarbeiter from "./Vertraege.js";
import VerticalSplit from "../verticalsplit/verticalsplit.js";
import ApiCoreVertraege from '../../api/factory/vertraege/vertraege.js';
export default {
name: 'Vertragsverwaltung',
components: {
+1
View File
@@ -0,0 +1 @@
../vendor
+343
View File
@@ -60360,6 +60360,349 @@ I have been informed that I am under no obligation to consent to the transmissio
)
),
// generic tabulator phrases END
// PHRASES ZEITSPERREN START
array(
'app' => 'core',
'category' => 'zeitsperren',
'phrase' => 'btn_all_current',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Aktuelle Zeitsperren',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Current Timelocks',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'zeitsperren',
'phrase' => 'btn_all_fix',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Alle Fixangestellten',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'All permanent employees',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'zeitsperren',
'phrase' => 'btn_fix_lect',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Alle fixen Lektor*innen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'All permanent lecturers',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'zeitsperren',
'phrase' => 'btn_oes',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Nach Organisationseinheit',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'By organizational unit',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'zeitsperren',
'phrase' => 'btn_all_ass',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Alle Assistent*innen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'All Assistants',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'zeitsperren',
'phrase' => 'btn_lect_stg',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Lektor*innen nach Stg',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Lecturers by study program',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'zeitsperren',
'phrase' => 'title_allMa',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Mitarbeiter*innen mit aktuellen Zeitsperren',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Employees with current time blocks',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'zeitsperren',
'phrase' => 'title_fix',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Zeitsperren Fixangestellte',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Time blocks permanent employees',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'zeitsperren',
'phrase' => 'title_fixLecturers',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Zeitsperren aller fixer Lektoren',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Time blocks for all regular lecturers',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'zeitsperren',
'phrase' => 'title_byOe',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Zeitsperren nach Organisationseinheit',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Time blocks by organizational unit',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'zeitsperren',
'phrase' => 'title_lectStg',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Zeitsperren Lektor*innen nach Studiengang',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Time blocks lecturers by study program',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'zeitsperren',
'phrase' => 'title_ass',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Zeitsperren aller Assistent*innen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Time blocks for all assistants',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'zeitsperren',
'phrase' => 'lektor_innen',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Lektor*innen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Lecturers',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'zeitsperren',
'phrase' => 'abwesend',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'abwesend',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'absent',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'zeitsperren',
'phrase' => 'anzahlTage',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Anzahl Tage',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Number of days',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'zeitsperren',
'phrase' => 'zeitsperrenVon',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Zeitsperren von',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Timelocks from',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'error_paramNoNumber',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Parameter {param} muss eine Zahl sein',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Parameter {param} has to be a number',
'description' => '',
'insertvon' => 'system'
)
)
),
// PHRASES ZEITSPERREN END
);