mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-22 17:32:18 +00:00
add tempus kalender tags
This commit is contained in:
@@ -125,6 +125,8 @@ $route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/person/(:num)'] = 'api/f
|
||||
// load routes from extensions, also look for environment-specific configs
|
||||
$subdirs = ['application/config/extensions', 'application/config/' . ENVIRONMENT . '/extensions'];
|
||||
|
||||
$route['api/frontend/v1/tempus/Tags/getTagsByCalendar/(:num)'] = 'api/frontend/v1/tempus/Tags/getTagsByCalendar/$1';
|
||||
|
||||
foreach($subdirs as $subdir)
|
||||
{
|
||||
if(is_dir($subdir))
|
||||
|
||||
@@ -2,4 +2,11 @@
|
||||
|
||||
$config['send_update_mails'] = false;
|
||||
$config['calendar_start'] = 7;
|
||||
$config['calendar_end'] = 23;
|
||||
$config['calendar_end'] = 23;
|
||||
|
||||
|
||||
$config['tempus_tags'] = [
|
||||
'prioone' => ['readonly' => false],
|
||||
'priotwo' => ['readonly' => true],
|
||||
'hinweis' => ['readonly' => false],
|
||||
];
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
if (!defined('BASEPATH'))
|
||||
exit('No direct script access allowed');
|
||||
|
||||
class Tags extends Tag_Controller
|
||||
{
|
||||
const BERECHTIGUNG_KURZBZ = ['admin:rw', 'assistenz:rw'];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'getTag' => self::BERECHTIGUNG_KURZBZ,
|
||||
'getTags' => self::BERECHTIGUNG_KURZBZ,
|
||||
'getTagsByCalendar' => self::BERECHTIGUNG_KURZBZ,
|
||||
'addTag' => self::BERECHTIGUNG_KURZBZ,
|
||||
'updateTag' => self::BERECHTIGUNG_KURZBZ,
|
||||
'doneTag' => self::BERECHTIGUNG_KURZBZ,
|
||||
'deleteTag' => self::BERECHTIGUNG_KURZBZ
|
||||
]);
|
||||
|
||||
$this->config->load('tempus');
|
||||
}
|
||||
|
||||
public function getTag($readonly_tags = null)
|
||||
{
|
||||
parent::getTag($this->config->item('tempus_tags'));
|
||||
}
|
||||
public function getTags($tags = null)
|
||||
{
|
||||
parent::getTags($this->config->item('tempus_tags'));
|
||||
}
|
||||
public function getTagsByCalendar($eindeutige_kalender_gruppen_id = null)
|
||||
{
|
||||
parent::getTagsByAssignmentTypeValue('eindeutige_kalender_gruppen_id', $eindeutige_kalender_gruppen_id, $this->config->item('tempus_tags'));
|
||||
}
|
||||
public function addTag($withZuordnung = true, $updatable_tags = null)
|
||||
{
|
||||
parent::addTag(true, $this->config->item('tempus_tags'));
|
||||
}
|
||||
public function updateTag($updatable_tags = null)
|
||||
{
|
||||
parent::updateTag($this->config->item('tempus_tags'));
|
||||
}
|
||||
public function deleteTag($withZuordnung = true, $updatable_tags = null)
|
||||
{
|
||||
parent::deleteTag(true, $this->config->item('tempus_tags'));
|
||||
}
|
||||
public function doneTag($updatable_tags = null)
|
||||
{
|
||||
parent::doneTag($this->config->item('tempus_tags'));
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,33 @@ class Tag_Controller extends FHCAPI_Controller
|
||||
$notiztypen = $this->NotiztypModel->loadWhere(array('aktiv' => true));
|
||||
$this->terminateWithSuccess(hasData($notiztypen) ? getData($notiztypen) : array());
|
||||
}
|
||||
public function getTagsByAssignmentTypeValue($zuordnung_typ, $zuordnung_id, $tags = null)
|
||||
{
|
||||
$this->NotizzuordnungModel->addSelect(
|
||||
'tbl_notizzuordnung.notiz_id as notiz_id,
|
||||
typ_kurzbz as tag_typ_kurzbz,
|
||||
array_to_json(bezeichnung_mehrsprachig::varchar[])->>0 as bezeichnung,
|
||||
style,
|
||||
beschreibung,
|
||||
tag,
|
||||
tbl_notiz.erledigt as done
|
||||
'
|
||||
);
|
||||
|
||||
if (is_array($tags) && !isEmptyArray($tags))
|
||||
{
|
||||
$tags = $this->_filterTag($tags, false);
|
||||
$this->NotizzuordnungModel->db->where_in('tbl_notiz_typ.typ_kurzbz', $tags);
|
||||
}
|
||||
|
||||
$this->NotizzuordnungModel->addJoin('public.tbl_notiz', 'public.tbl_notizzuordnung.notiz_id = public.tbl_notiz.notiz_id');
|
||||
$this->NotizzuordnungModel->addJoin('public.tbl_notiz_typ', 'public.tbl_notiz.typ = public.tbl_notiz_typ.typ_kurzbz');
|
||||
|
||||
$this->NotizzuordnungModel->addOrder('prioritaet');
|
||||
|
||||
$notiztypen = $this->NotizzuordnungModel->loadWhere(array('aktiv' => true, $zuordnung_typ => $zuordnung_id));
|
||||
$this->terminateWithSuccess(hasData($notiztypen) ? getData($notiztypen) : array());
|
||||
}
|
||||
public function addTag($withZuordnung = true, $updatable_tags = null)
|
||||
{
|
||||
$postData = $this->getPostJson();
|
||||
@@ -126,7 +152,7 @@ class Tag_Controller extends FHCAPI_Controller
|
||||
if (!in_array($postData->tag_typ_kurzbz, $tags))
|
||||
$this->terminateWithError($this->p->t('ui', 'keineBerechtigung'));
|
||||
}
|
||||
|
||||
|
||||
if ($withZuordnung)
|
||||
{
|
||||
$return = array();
|
||||
@@ -135,7 +161,7 @@ class Tag_Controller extends FHCAPI_Controller
|
||||
$this->terminateWithError('Error occurred', self::ERROR_TYPE_GENERAL);
|
||||
|
||||
$values = array_unique($postData->values);
|
||||
|
||||
|
||||
foreach ($values as $value)
|
||||
{
|
||||
$insertResult = $this->addNotiz($postData);
|
||||
|
||||
@@ -39,56 +39,56 @@ class KalenderLib
|
||||
$end_date = date('Y-m-d', strtotime($end_date . ' +1 day'));
|
||||
|
||||
$this->_ci->KalenderModel->addSelect('tbl_kalender.kalender_id,
|
||||
tbl_kalender.eindeutige_gruppen_id,
|
||||
tbl_kalender.status_kurzbz,
|
||||
tbl_kalender.typ,
|
||||
tbl_kalender.von,
|
||||
tbl_kalender.bis,
|
||||
tbl_kalender_ort.ort_kurzbz,
|
||||
tbl_lehreinheit.lehreinheit_id,
|
||||
tbl_lehreinheit.lehrveranstaltung_id,
|
||||
tbl_lehreinheit.lehrfach_id,
|
||||
tbl_lehreinheit.lehrform_kurzbz,
|
||||
tbl_lehrveranstaltung.oe_kurzbz,
|
||||
lehrfach.kurzbz AS lehrfach_kurzbz,
|
||||
lehrfach.bezeichnung AS lehrfach_bezeichnung,
|
||||
lehrfach.farbe,
|
||||
COALESCE(orginasator.uid, tbl_lehreinheitmitarbeiter.mitarbeiter_uid) as mitarbeiter_uid,
|
||||
COALESCE(reservierung_person.vorname, tbl_person.vorname) as vorname,
|
||||
COALESCE(reservierung_person.nachname, tbl_person.nachname) as nachname,
|
||||
COALESCE(reservierung_ma.kurzbz, tbl_mitarbeiter.kurzbz) AS ma_kurzbz,
|
||||
teilnehmergruppe.gruppe_kurzbz as teilnehmerg_grp,
|
||||
COALESCE (
|
||||
UPPER(tbl_studiengang.typ || tbl_studiengang.kurzbz) ||
|
||||
COALESCE(verbandgruppe.semester::varchar, \'\') ||
|
||||
COALESCE(verbandgruppe.verband::varchar, \'\') ||
|
||||
COALESCE(verbandgruppe.gruppe, \'\'),
|
||||
\'\') as verband_grp,
|
||||
tbl_kalender_event.beschreibung,
|
||||
tbl_kalender_event.titel,
|
||||
teilmitarbeiter.kurzbz as teilnehmer_kurzbz,
|
||||
teilperson.vorname as teilnehmer_vorname,
|
||||
teilperson.nachname as teilnehmer_nachname,
|
||||
teilbenutzer.uid as teilnehmer_uid,
|
||||
CASE
|
||||
WHEN tbl_lehreinheitgruppe.gruppe_kurzbz IS NULL THEN
|
||||
COALESCE(
|
||||
UPPER(le_studiengang.typ || le_studiengang.kurzbz) ||
|
||||
COALESCE(tbl_lehreinheitgruppe.semester::varchar, \'\') ||
|
||||
COALESCE(tbl_lehreinheitgruppe.verband::varchar, \'\') ||
|
||||
COALESCE(tbl_lehreinheitgruppe.gruppe, \'\'),
|
||||
\'\')
|
||||
ELSE tbl_lehreinheitgruppe.gruppe_kurzbz
|
||||
END AS lehreinheit_gruppe_bezeichnung,
|
||||
tbl_lehreinheitgruppe.gruppe_kurzbz as le_gruppe_kurzbz,
|
||||
tbl_lehreinheitgruppe.studiengang_kz as le_studiengang_kz,
|
||||
tbl_lehreinheitgruppe.semester as le_semester,
|
||||
tbl_lehreinheitgruppe.verband as le_verband,
|
||||
tbl_lehreinheitgruppe.gruppe as le_gruppe,
|
||||
le_gruppe.direktinskription as le_direktinskription,
|
||||
|
||||
|
||||
');
|
||||
tbl_kalender.eindeutige_gruppen_id,
|
||||
tbl_kalender.status_kurzbz,
|
||||
tbl_kalender.typ,
|
||||
tbl_kalender.von,
|
||||
tbl_kalender.bis,
|
||||
tbl_kalender_ort.ort_kurzbz,
|
||||
tbl_lehreinheit.lehreinheit_id,
|
||||
tbl_lehreinheit.lehrveranstaltung_id,
|
||||
tbl_lehreinheit.lehrfach_id,
|
||||
tbl_lehreinheit.lehrform_kurzbz,
|
||||
tbl_lehrveranstaltung.oe_kurzbz,
|
||||
lehrfach.kurzbz AS lehrfach_kurzbz,
|
||||
lehrfach.bezeichnung AS lehrfach_bezeichnung,
|
||||
lehrfach.farbe,
|
||||
COALESCE(orginasator.uid, tbl_lehreinheitmitarbeiter.mitarbeiter_uid) as mitarbeiter_uid,
|
||||
COALESCE(reservierung_person.vorname, tbl_person.vorname) as vorname,
|
||||
COALESCE(reservierung_person.nachname, tbl_person.nachname) as nachname,
|
||||
COALESCE(reservierung_ma.kurzbz, tbl_mitarbeiter.kurzbz) AS ma_kurzbz,
|
||||
teilnehmergruppe.gruppe_kurzbz as teilnehmerg_grp,
|
||||
COALESCE (
|
||||
UPPER(tbl_studiengang.typ || tbl_studiengang.kurzbz) ||
|
||||
COALESCE(verbandgruppe.semester::varchar, \'\') ||
|
||||
COALESCE(verbandgruppe.verband::varchar, \'\') ||
|
||||
COALESCE(verbandgruppe.gruppe, \'\'),
|
||||
\'\') as verband_grp,
|
||||
tbl_kalender_event.beschreibung,
|
||||
tbl_kalender_event.titel,
|
||||
teilmitarbeiter.kurzbz as teilnehmer_kurzbz,
|
||||
teilperson.vorname as teilnehmer_vorname,
|
||||
teilperson.nachname as teilnehmer_nachname,
|
||||
teilbenutzer.uid as teilnehmer_uid,
|
||||
CASE
|
||||
WHEN tbl_lehreinheitgruppe.gruppe_kurzbz IS NULL THEN
|
||||
COALESCE(
|
||||
UPPER(le_studiengang.typ || le_studiengang.kurzbz) ||
|
||||
COALESCE(tbl_lehreinheitgruppe.semester::varchar, \'\') ||
|
||||
COALESCE(tbl_lehreinheitgruppe.verband::varchar, \'\') ||
|
||||
COALESCE(tbl_lehreinheitgruppe.gruppe, \'\'),
|
||||
\'\')
|
||||
ELSE tbl_lehreinheitgruppe.gruppe_kurzbz
|
||||
END AS lehreinheit_gruppe_bezeichnung,
|
||||
tbl_lehreinheitgruppe.gruppe_kurzbz as le_gruppe_kurzbz,
|
||||
tbl_lehreinheitgruppe.studiengang_kz as le_studiengang_kz,
|
||||
tbl_lehreinheitgruppe.semester as le_semester,
|
||||
tbl_lehreinheitgruppe.verband as le_verband,
|
||||
tbl_lehreinheitgruppe.gruppe as le_gruppe,
|
||||
le_gruppe.direktinskription as le_direktinskription,
|
||||
tag_data_agg.tags as tags,
|
||||
resource_data_agg.resources as resources
|
||||
');
|
||||
|
||||
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit', 'tbl_kalender.kalender_id = tbl_kalender_lehreinheit.kalender_id', 'LEFT');
|
||||
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event', 'tbl_kalender.kalender_id = tbl_kalender_event.kalender_id', 'LEFT');
|
||||
@@ -134,6 +134,69 @@ class KalenderLib
|
||||
);
|
||||
$this->_ci->KalenderModel->addJoin('public.tbl_studiengang le_studiengang', 'le_lehrverband.studiengang_kz = le_studiengang.studiengang_kz', 'LEFT');
|
||||
|
||||
// Include tags in the query
|
||||
$this->_ci->load->config('tempus');
|
||||
$tags = $this->_ci->config->item('tempus_tags');
|
||||
|
||||
$whereTags = '';
|
||||
if (is_array($tags) && !isEmptyArray($tags)) {
|
||||
$tags = array_keys($tags);
|
||||
|
||||
foreach ($tags as $key => $tag) {
|
||||
$tags[$key] = $this->_ci->KalenderModel->escape($tag);
|
||||
}
|
||||
$whereTags = " AND nt.typ_kurzbz IN (" . implode(",", $tags) . ")";
|
||||
}
|
||||
$subQueryTag = "(
|
||||
SELECT
|
||||
tag.eindeutige_kalender_gruppen_id,
|
||||
COALESCE(json_agg(tag ORDER BY tag.done, tag.prioritaet), '[]'::json) AS tags
|
||||
FROM (
|
||||
SELECT DISTINCT ON (n.notiz_id)
|
||||
n.notiz_id AS id,
|
||||
nt.typ_kurzbz,
|
||||
array_to_json(nt.bezeichnung_mehrsprachig)->>0 AS beschreibung,
|
||||
n.text AS notiz,
|
||||
nt.style,
|
||||
n.erledigt AS done,
|
||||
nt.prioritaet AS prioritaet,
|
||||
nz.eindeutige_kalender_gruppen_id
|
||||
FROM public.tbl_notizzuordnung AS nz
|
||||
JOIN public.tbl_notiz AS n ON nz.notiz_id = n.notiz_id
|
||||
JOIN public.tbl_notiz_typ AS nt ON n.typ = nt.typ_kurzbz " . $whereTags . "
|
||||
) AS tag
|
||||
GROUP BY tag.eindeutige_kalender_gruppen_id
|
||||
) AS tag_data_agg";
|
||||
|
||||
$this->_ci->KalenderModel->addJoin($subQueryTag, 'tag_data_agg.eindeutige_kalender_gruppen_id = tbl_kalender.eindeutige_gruppen_id', 'LEFT');
|
||||
// End of tags inclusion
|
||||
|
||||
// Include assigned operational resources in the query
|
||||
$subQueryResource = "(
|
||||
SELECT
|
||||
resource.eindeutige_kalender_gruppen_id,
|
||||
COALESCE(json_agg(resource ORDER BY resource.beschreibung), '[]'::json) AS resources
|
||||
FROM (
|
||||
SELECT
|
||||
betriebsmittel_kalender.*,
|
||||
betriebsmittel.beschreibung,
|
||||
betriebsmittel.verplanen
|
||||
FROM lehre.tbl_betriebsmittel_kalender AS betriebsmittel_kalender
|
||||
JOIN wawi.tbl_betriebsmittel AS betriebsmittel
|
||||
ON betriebsmittel.betriebsmittel_id = betriebsmittel_kalender.betriebsmittel_id
|
||||
WHERE betriebsmittel.verplanen = TRUE
|
||||
) AS resource
|
||||
GROUP BY resource.eindeutige_kalender_gruppen_id
|
||||
) AS resource_data_agg";
|
||||
|
||||
$this->_ci->KalenderModel->addJoin(
|
||||
$subQueryResource,
|
||||
'resource_data_agg.eindeutige_kalender_gruppen_id = tbl_kalender.eindeutige_gruppen_id',
|
||||
'LEFT'
|
||||
);
|
||||
// End of operational resources inclusion
|
||||
|
||||
|
||||
$this->_ci->KalenderModel->db->where('tbl_kalender.von >=', $start_date);
|
||||
$this->_ci->KalenderModel->db->where('tbl_kalender.bis <', $end_date);
|
||||
|
||||
@@ -157,6 +220,8 @@ class KalenderLib
|
||||
{
|
||||
$von = new DateTime($row->von);
|
||||
$bis = new DateTime($row->bis);
|
||||
$resources = isset($row->resources) ? $row->resources : [];
|
||||
$parsedResources = is_string($resources) ? json_decode($resources, true) : $resources;
|
||||
|
||||
$events[$id] = (object) [
|
||||
'eindeutige_gruppen_id' => $row->eindeutige_gruppen_id,
|
||||
@@ -185,7 +250,9 @@ class KalenderLib
|
||||
'beschreibung' => isset($row->beschreibung) ? $row->beschreibung : '',
|
||||
'topic' => [],
|
||||
'collisions' => false,
|
||||
'has_assigned_resources' => isset($row->has_assigned_resources) ? $row->has_assigned_resources : false,
|
||||
'has_assigned_resources' => !empty($parsedResources),
|
||||
'resources' => is_array($parsedResources) ? $parsedResources : [],
|
||||
'tags' => isset($row->tags) ? $row->tags : [],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -443,13 +510,6 @@ class KalenderLib
|
||||
|
||||
$this->_ci->KalenderModel->db->where_not_in('status_kurzbz', array('deleted'));
|
||||
|
||||
$this->_ci->KalenderModel->addSelect([
|
||||
"(
|
||||
SELECT COUNT(*) FROM lehre.tbl_betriebsmittel_kalender
|
||||
WHERE tbl_betriebsmittel_kalender.eindeutige_kalender_gruppen_id = tbl_kalender.eindeutige_gruppen_id
|
||||
) AS has_assigned_resources"
|
||||
]);
|
||||
|
||||
$data = $this->_ci->KalenderModel->load();
|
||||
|
||||
return $this->_mapEvents($data);
|
||||
@@ -961,16 +1021,6 @@ class KalenderLib
|
||||
}
|
||||
}
|
||||
|
||||
/* foreach ($specialGroups as $group)
|
||||
{
|
||||
$this->_addSpecialGroupToEvent($kalender_id, $group['gruppe_kurzbz'], $group['rolle']);
|
||||
}
|
||||
|
||||
foreach ($groups as $group)
|
||||
{
|
||||
$this->_addGroupToEvent($kalender_id, $group['stg_kz'], $group['semester'], $group['verband'], $group['gruppe'], $group['rolle']);
|
||||
}*/
|
||||
|
||||
if (isSuccess($kalendereventresult) && !is_null($ort_kurzbz))
|
||||
{
|
||||
$ortresult = $this->_addKalenderOrt($kalender_id, $ort_kurzbz);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
'primevue3' => true,
|
||||
'tabulator5' => true,
|
||||
'vuedatepicker11' => true,
|
||||
'tags' => true,
|
||||
'phrases' => array(
|
||||
'global',
|
||||
'ui',
|
||||
|
||||
@@ -86,6 +86,9 @@
|
||||
pointer-events: none;
|
||||
background-color: transparent !important;
|
||||
border: none !important;
|
||||
width: fit-content;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.fhc-resize-bar--top {
|
||||
|
||||
@@ -17,6 +17,13 @@
|
||||
transform: scale(1.15);
|
||||
}
|
||||
|
||||
/* add prop that disasbles hover and cursor*/
|
||||
.tag.disabled:hover
|
||||
{
|
||||
transform: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.tag_rot {
|
||||
background-color: #ff0000ff;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
export default {
|
||||
|
||||
getTag(data)
|
||||
{
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/tempus/Tags/getTag',
|
||||
params: data
|
||||
};
|
||||
},
|
||||
|
||||
getTags(data)
|
||||
{
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/tempus/Tags/getTags'
|
||||
};
|
||||
},
|
||||
getTagsByCalendar(calenderGroupId)
|
||||
{
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/tempus/Tags/getTagsByCalendar/' + calenderGroupId,
|
||||
};
|
||||
},
|
||||
addTag(data)
|
||||
{
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/tempus/Tags/addTag',
|
||||
params: data
|
||||
};
|
||||
},
|
||||
updateTag(data)
|
||||
{
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/tempus/Tags/updateTag',
|
||||
params: data
|
||||
};
|
||||
},
|
||||
doneTag(data)
|
||||
{
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/tempus/Tags/doneTag',
|
||||
params: data
|
||||
};
|
||||
},
|
||||
|
||||
deleteTag(data)
|
||||
{
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/tempus/Tags/deleteTag',
|
||||
params: data
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -14,6 +14,10 @@ export default {
|
||||
'deleted',
|
||||
],
|
||||
props: {
|
||||
isListItemShown: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
endpoint: {
|
||||
type: Object,
|
||||
required: true
|
||||
@@ -206,7 +210,7 @@ export default {
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="plus_button_container" @mouseleave="hideList">
|
||||
<div v-if="isListItemShown" class="plus_button_container" @mouseleave="hideList">
|
||||
<span :title="values.length === 0 ? 'Bitte Zeilen markieren' : ''">
|
||||
<button @mouseover="showList = true"
|
||||
:disabled="!values || values.length === 0"
|
||||
|
||||
@@ -77,7 +77,43 @@ export default {
|
||||
return luxon.Duration
|
||||
.fromISOTime(this.event.ende)
|
||||
.toISOTime({ suppressSeconds: true });
|
||||
}
|
||||
},
|
||||
tags() {
|
||||
if (typeof this.event.tags === 'string') {
|
||||
try {
|
||||
return JSON.parse(this.event.tags);
|
||||
} catch (e) {
|
||||
console.error('Failed to parse tags:', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return this.event.tags || [];
|
||||
},
|
||||
tagsTooltip() {
|
||||
if (this.tags.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return this.tags.map(tag => tag.beschreibung).join("\n");
|
||||
},
|
||||
resourcesTooltip() {
|
||||
if (!this.event.resources || this.event.resources.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let resources = this.event.resources;
|
||||
if (typeof this.event.resources === 'string') {
|
||||
try {
|
||||
resources = JSON.parse(this.event.resources);
|
||||
} catch (e) {
|
||||
console.error('Failed to parse resources:', e);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
return resources.map(resource => resource.beschreibung).join("\n");
|
||||
},
|
||||
},
|
||||
template: /*html*/`
|
||||
<div
|
||||
@@ -85,9 +121,16 @@ export default {
|
||||
class="position-relative"
|
||||
@wheel.stop
|
||||
>
|
||||
<div v-if="event.has_assigned_resources" class="position-absolute top-0 start-0 m-1" >
|
||||
<div v-if="event.has_assigned_resources || tags?.length" class="position-absolute top-0 start-0 m-1 d-flex gap-1" >
|
||||
<i
|
||||
class="fa-solid fa-table-list text-muted"
|
||||
v-tooltip="resourcesTooltip"
|
||||
v-if="event.has_assigned_resources"
|
||||
class="fa-solid fa-table-list text-muted"
|
||||
></i>
|
||||
<i
|
||||
v-tooltip="tagsTooltip"
|
||||
v-if="tags?.length"
|
||||
class="fa-solid fa-tags"
|
||||
></i>
|
||||
</div>
|
||||
<div
|
||||
|
||||
@@ -53,6 +53,31 @@ export default {
|
||||
ortString() {
|
||||
return Array.isArray(this.event.ort_kurzbz) ? this.event.ort_kurzbz.join(', ') : this.event.ort_kurzbz;
|
||||
},
|
||||
tags() {
|
||||
if (typeof this.event.tags === 'string') {
|
||||
try {
|
||||
return JSON.parse(this.event.tags);
|
||||
} catch (e) {
|
||||
console.error('Failed to parse tags:', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return this.event.tags || [];
|
||||
},
|
||||
resourcesValue() {
|
||||
let resources = this.event.resources;
|
||||
if (typeof this.event.resources === 'string') {
|
||||
try {
|
||||
resources = JSON.parse(this.event.resources);
|
||||
} catch (e) {
|
||||
console.error('Failed to parse resources:', e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return resources.map(resource => resource.beschreibung).join(', ');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
mehtodNumberPadding: function (number) {
|
||||
@@ -78,7 +103,7 @@ export default {
|
||||
});
|
||||
}
|
||||
},
|
||||
template: `
|
||||
template: /*html*/`
|
||||
<div>
|
||||
<h5>
|
||||
{{$p.t('lvinfo','lehrveranstaltungsinformationen')}}
|
||||
@@ -143,6 +168,33 @@ export default {
|
||||
}}</th>
|
||||
<td>{{event.organisationseinheit}}</td>
|
||||
</tr>
|
||||
<tr v-if="resourcesValue">
|
||||
<th>{{
|
||||
$p.t('ui','betriebsmittel')?
|
||||
$p.t('ui','betriebsmittel')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<td>
|
||||
{{ resourcesValue }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="tags.length">
|
||||
<th>{{
|
||||
$p.t('ui','tags')?
|
||||
$p.t('ui','tags')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<td>
|
||||
<div>
|
||||
<span
|
||||
v-for="tag in tags"
|
||||
:key="tag.tag_typ_kurzbz"
|
||||
:class="[tag.style, { tag_done: tag.done }]"
|
||||
class="tag disabled"
|
||||
>{{ tag.beschreibung }}</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import ApiRenderers from "../../api/factory/renderers.js";
|
||||
import ApiTempusConfig from "../../api/factory/tempus/config.js";
|
||||
import ApiBetriebsmittel from "../../api/factory/betriebsmittel.js";
|
||||
import ApiOperationalResourceToCalender from "../../api/factory/operationalResourceToCalender.js";
|
||||
import ApiTempusTag from "../../api/factory/tempus/tag.js";
|
||||
import AppMenu from "../AppMenu.js";
|
||||
import drop from "../../directives/drop.js";
|
||||
import AppConfig from "../AppConfig.js";
|
||||
@@ -46,6 +47,7 @@ import KeyboardShortcuts from "./KeyboardShortcuts.js";
|
||||
import { useContextMenuActions } from "../../composables/Tempus/ContextMenuActions.js";
|
||||
import MultiWeekPlanModal from "./MultiWeekPlanModal.js";
|
||||
import { getTempusSearchbarOptions } from "./Filters/searchbarOptions.js";
|
||||
import CoreTag from '../Tag/Tag.js';
|
||||
|
||||
export default {
|
||||
name: "Tempus",
|
||||
@@ -69,6 +71,7 @@ export default {
|
||||
Reservierung,
|
||||
KeyboardShortcuts,
|
||||
MultiWeekPlanModal,
|
||||
CoreTag,
|
||||
},
|
||||
props: {
|
||||
defaultSemester: String,
|
||||
@@ -93,8 +96,9 @@ export default {
|
||||
appConfig: Vue.computed(() => this.appconfig),
|
||||
contextMenuActions: useContextMenuActions({
|
||||
openRaumauswahl: (orig) => this.openRaumauswahl(orig),
|
||||
openResourcesAssignmentModal: (orig) =>
|
||||
openResourcesAssignmentModal: (orig) =>
|
||||
this.openResourcesAssignmentModal(orig),
|
||||
openTagsModal: (orig) => this.openTagsAssignmentModal(orig),
|
||||
openHistory: (orig) => this.openHistory(orig),
|
||||
deleteEntry: (orig) => this.deleteEntry(orig),
|
||||
syncToLecturer: (orig) => this.syncToLecturer(orig),
|
||||
@@ -171,6 +175,15 @@ export default {
|
||||
assignedResources: [],
|
||||
areFormButtonsDisplayed: false,
|
||||
},
|
||||
tagsAssignmentModal: {
|
||||
calendar: null,
|
||||
availableTags: [],
|
||||
filteredAvailableTags: [],
|
||||
selectedAvailableTag: null,
|
||||
assignedTags: [],
|
||||
areFormButtonsDisplayed: false,
|
||||
},
|
||||
tagEndpoint: ApiTempusTag,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -216,6 +229,16 @@ export default {
|
||||
})
|
||||
.sort((a, b) => a.label?.localeCompare(b.label));
|
||||
},
|
||||
dropdownParsedAvailableTags() {
|
||||
return this.tagsAssignmentModal.availableTags
|
||||
.map((tag) => {
|
||||
return {
|
||||
label: tag.bezeichnung,
|
||||
value: tag.tag_typ_kurzbz,
|
||||
data: tag,
|
||||
};
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async openRaumauswahl(orig) {
|
||||
@@ -244,6 +267,19 @@ export default {
|
||||
|
||||
this.$refs.resourcesAssignmentModal.show();
|
||||
},
|
||||
async openTagsAssignmentModal(orig) {
|
||||
console.log("openTagsAssignmentModal called with orig:", orig);
|
||||
if (!orig?.kalender_id) return;
|
||||
|
||||
this.tagsAssignmentModal.calendar = orig;
|
||||
this.tagsAssignmentModal.availableTags = await this.fetchAvailableTags();
|
||||
this.tagsAssignmentModal.filteredAvailableTags = [
|
||||
...this.dropdownParsedAvailableTags,
|
||||
];
|
||||
|
||||
this.tagsAssignmentModal.assignedTags = await this.fetchAssignedTagsByCalender(orig.eindeutige_gruppen_id);
|
||||
this.$refs.tagsAssignmentModal.show();
|
||||
},
|
||||
async deleteEntry(orig) {
|
||||
if (!orig?.kalender_id) return;
|
||||
|
||||
@@ -891,7 +927,7 @@ export default {
|
||||
this.resourcesAssignmentModal.selectedAvailableResource = null;
|
||||
this.resourcesAssignmentModal.areFormButtonsDisplayed = false;
|
||||
},
|
||||
async saveAssignedResourcesToCalendarItem(calenderItem, assignedResources) {
|
||||
async saveAssignedResourcesToCalendarItem(calenderItem, assignedResources) {
|
||||
let getSchedulableResourcesByCalendar = await this.$api.call(
|
||||
ApiOperationalResourceToCalender.storeResourcesToCalendarRelationship(
|
||||
calenderItem.kalender_id,
|
||||
@@ -921,6 +957,114 @@ export default {
|
||||
areFormButtonsDisplayed: false,
|
||||
};
|
||||
},
|
||||
async fetchAvailableTags() {
|
||||
let getAvailableTags = await this.$api.call(
|
||||
ApiTempusTag.getTags(),
|
||||
);
|
||||
if (getAvailableTags.meta.status === "success") {
|
||||
return getAvailableTags.data;
|
||||
} else {
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("ui", "failed_available_tags_fetch_error_message"),
|
||||
);
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
async fetchAssignedTagsByCalender(calenderId) {
|
||||
let getAssignedTags = await this.$api.call(
|
||||
ApiTempusTag.getTagsByCalendar(calenderId),
|
||||
);
|
||||
if (getAssignedTags.meta.status === "success") {
|
||||
return getAssignedTags.data.filter((unit) => !!unit);
|
||||
} else {
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("ui", "failed_assigned_tags_fetch_error_message"),
|
||||
);
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
filterAvailableTags(event) {
|
||||
this.tagsAssignmentModal.filteredAvailableTags;
|
||||
const query = event.query.toLowerCase();
|
||||
if (!query) {
|
||||
return (this.tagsAssignmentModal.filteredAvailableTags = [
|
||||
...this.dropdownParsedAvailableTags.filter((tag) => {
|
||||
return !this.tagsAssignmentModal.assignedTags.some(
|
||||
(assigned) => assigned.tag_id === tag.value,
|
||||
);
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
return (this.tagsAssignmentModal.filteredAvailableTags =
|
||||
this.dropdownParsedAvailableTags
|
||||
.filter((tag) => {
|
||||
return !this.tagsAssignmentModal.assignedTags.some(
|
||||
(assigned) => assigned.tag_id === tag.value,
|
||||
);
|
||||
})
|
||||
.filter((tag) => {
|
||||
return tag.label.toLowerCase().includes(query);
|
||||
}));
|
||||
},
|
||||
removeAssignedTag(tag) {
|
||||
this.tagsAssignmentModal.assignedTags =
|
||||
this.tagsAssignmentModal.assignedTags.filter(
|
||||
(assigned) => assigned.tag_id !== tag.tag_id,
|
||||
);
|
||||
|
||||
this.tagsAssignmentModal.areFormButtonsDisplayed = true;
|
||||
},
|
||||
async refreshTagsAssignmentModalData(calenderItem) {
|
||||
this.tagsAssignmentModal.availableTags =
|
||||
await this.fetchAvailableTags();
|
||||
this.tagsAssignmentModal.filteredAvailableTags = [
|
||||
...this.dropdownParsedAvailableTags,
|
||||
];
|
||||
|
||||
this.tagsAssignmentModal.assignedTags =
|
||||
await this.fetchAssignedTagsByCalender(calenderItem.eindeutige_gruppen_id);
|
||||
this.tagsAssignmentModal.selectedAvailableTag = null;
|
||||
this.tagsAssignmentModal.areFormButtonsDisplayed = false;
|
||||
},
|
||||
async saveAssignedTagsToCalendarItem(calenderItem, assignedTags) {
|
||||
let saveAssignedTagsByCalender = await this.$api.call(
|
||||
ApiTempusTag.getTags(
|
||||
calenderItem.eindeutige_gruppen_id,
|
||||
assignedTags,
|
||||
),
|
||||
);
|
||||
if (saveAssignedTagsByCalender.meta.status === "success") {
|
||||
this.$fhcAlert.alertSuccess(
|
||||
this.$p.t("ui", "assigned_tags_save_success_message"),
|
||||
);
|
||||
await this.refreshTagsAssignmentModalData(calenderItem);
|
||||
} else {
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("ui", "failed_assigned_tags_save_error_message"),
|
||||
);
|
||||
}
|
||||
|
||||
this.$refs.calendar.resetEventLoader();
|
||||
this.$refs.tagsAssignmentModal.hide();
|
||||
},
|
||||
closeTagsAssignmentModal() {
|
||||
this.tagsAssignmentModal = {
|
||||
availableTags: [],
|
||||
filteredAvailableTags: [],
|
||||
selectedAvailableTag: null,
|
||||
assignedTags: [],
|
||||
areFormButtonsDisplayed: false,
|
||||
};
|
||||
},
|
||||
async handleCalenderTagChange(calenderID) {
|
||||
this.tagsAssignmentModal.assignedTags =
|
||||
await this.fetchAssignedTagsByCalender(calenderID);
|
||||
|
||||
this.$refs.calendar.resetEventLoader();
|
||||
},
|
||||
removeLecturer(uid) {
|
||||
if (uid == null) {
|
||||
for (const lect of this.lecturers) delete this.overlayCache[lect.uid];
|
||||
@@ -1079,7 +1223,7 @@ export default {
|
||||
this.studiengaenge_all = res.data;
|
||||
});
|
||||
},
|
||||
template: `
|
||||
template: /* html */`
|
||||
<div
|
||||
class="tempus"
|
||||
data-cy="tempus"
|
||||
@@ -1201,17 +1345,6 @@ export default {
|
||||
</button>
|
||||
</div>
|
||||
<div class="px-2 py-1 w-100">
|
||||
<!--<Multiselect
|
||||
:model-value="visibleStatusValue"
|
||||
@update:model-value="val => toggleStatus(val.map(o => o.key))"
|
||||
option-label="label"
|
||||
:options="visibleStatusOptions"
|
||||
placeholder="Status filtern"
|
||||
:hide-selected="false"
|
||||
:show-toggle-all="false"
|
||||
class="w-100"
|
||||
/>-->
|
||||
|
||||
<div
|
||||
class="d-flex gap-1 py-1"
|
||||
data-cy="previewRoleOptionsHolder"
|
||||
@@ -1385,6 +1518,54 @@ export default {
|
||||
<button type="button" class="btn btn-secondary" @click="refreshResourcesAssignmentModalData(resourcesAssignmentModal.calendar)">{{$p.t('ui', 'abbrechen')}}</button>
|
||||
<button type="button" class="btn btn-primary" @click="saveAssignedResourcesToCalendarItem(resourcesAssignmentModal.calendar, resourcesAssignmentModal.assignedResources)">{{$p.t('ui', 'speichern')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</bs-modal>
|
||||
<bs-modal
|
||||
ref="tagsAssignmentModal"
|
||||
@hideBsModal="closeTagsAssignmentModal"
|
||||
bodyClass="p-4"
|
||||
class="bootstrap-prompt"
|
||||
data-cy="tagsAssignmentModal"
|
||||
>
|
||||
<template #title>{{$p.t('ui', 'tags_assignment_modal_title')}}</template>
|
||||
<template #default>
|
||||
<div class="mb-5">
|
||||
<form-input
|
||||
v-if="tagsAssignmentModal.availableTags.length"
|
||||
@itemSelect="(option) => { tagsAssignmentModal.selectedAvailableTag = option.value; $refs.tagComponent.openModal(option.value.data); }"
|
||||
:label="$capitalize($p.t('ui', 'tags'))"
|
||||
:suggestions="tagsAssignmentModal.filteredAvailableTags"
|
||||
:optionValue="(option) => option.value"
|
||||
:optionLabel="(option) => option.label"
|
||||
@complete="filterAvailableTags"
|
||||
dropdown
|
||||
forceSelection
|
||||
type="autocomplete"
|
||||
name="availableTags"
|
||||
:closeOnSelect="false"
|
||||
>
|
||||
<template #option="{ option }">
|
||||
<span :class="['tag', option.data.style]">{{ option.label }}</span>
|
||||
</template>
|
||||
</form-input>
|
||||
</div>
|
||||
<div>
|
||||
<div class="d-flex align-items-center justify-content-between mb-2">
|
||||
<h6 class="mb-1 mx-auto text-bold fw-1">{{$p.t('ui', 'assigned_tags_subtitle')}}</h6>
|
||||
</div>
|
||||
<div v-if="tagsAssignmentModal.assignedTags.length">
|
||||
<span
|
||||
v-for="tag in tagsAssignmentModal.assignedTags"
|
||||
:key="tag.tag_typ_kurzbz"
|
||||
:class="[tag.style, { tag_done: tag.done }]"
|
||||
@click="$refs.tagComponent.editTag(tag.notiz_id)"
|
||||
class="tag"
|
||||
>{{ tag.bezeichnung }}</span>
|
||||
</div>
|
||||
<div v-else class="d-flex align-items-center justify-content-center mb-2">
|
||||
<p class="text-muted mb-0">{{$p.t('ui', 'no_assigned_tags')}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</bs-modal>
|
||||
@@ -1411,6 +1592,17 @@ export default {
|
||||
</table>
|
||||
</template>
|
||||
</bs-modal>
|
||||
<core-tag
|
||||
v-if="tagEndpoint && tagsAssignmentModal.calendar?.eindeutige_gruppen_id"
|
||||
ref="tagComponent"
|
||||
:isListItemShown="false"
|
||||
:endpoint="tagEndpoint"
|
||||
:values="[tagsAssignmentModal.calendar?.eindeutige_gruppen_id]"
|
||||
:zuordnung_typ="'eindeutige_kalender_gruppen_id'"
|
||||
@added="handleCalenderTagChange(tagsAssignmentModal.calendar?.eindeutige_gruppen_id)"
|
||||
@deleted="handleCalenderTagChange(tagsAssignmentModal.calendar?.eindeutige_gruppen_id)"
|
||||
@updated="handleCalenderTagChange(tagsAssignmentModal.calendar?.eindeutige_gruppen_id)"
|
||||
></core-tag>
|
||||
<reservierung
|
||||
ref="reservierung"
|
||||
:rooms="rooms"
|
||||
|
||||
@@ -12,6 +12,11 @@ export function useContextMenuActions(handlers)
|
||||
icon: 'fa-solid fa-table-list',
|
||||
action: handlers.openResourcesAssignmentModal
|
||||
},
|
||||
{
|
||||
label: 'Tags',
|
||||
icon: 'fa-solid fa-tags',
|
||||
action: handlers.openTagsModal
|
||||
},
|
||||
{
|
||||
label: 'Freischalten für Voransicht',
|
||||
icon: 'fa-solid fa-chalkboard-user',
|
||||
|
||||
@@ -100,6 +100,7 @@ require_once('dbupdate_3.4/76150_perm_other_lv_plan.php');
|
||||
require_once('dbupdate_3.4/68957_dashboard_bookmark_neue_Spalte_sort.php');
|
||||
require_once('dbupdate_3.4/68530_Dashboard_Cleanup.php');
|
||||
require_once('dbupdate_3.4/77375_ressourcen.php');
|
||||
require_once('dbupdate_3.4/78052_tempus_tag_events.php');
|
||||
// *** Pruefung und hinzufuegen der neuen Attribute und Tabellen
|
||||
echo '<H2>Pruefe Tabellen und Attribute!</H2>';
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
if (! defined('DB_NAME')) exit('No direct script access allowed');
|
||||
|
||||
$result = $db->db_query("SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'tbl_notizzuordnung'
|
||||
AND column_name = 'eindeutige_kalender_gruppen_id'");
|
||||
|
||||
if ($db->db_num_rows($result) === 0)
|
||||
{
|
||||
$qry = "ALTER TABLE public.tbl_notizzuordnung
|
||||
ADD COLUMN eindeutige_kalender_gruppen_id UUID NULL DEFAULT NULL";
|
||||
|
||||
if (!$db->db_query($qry))
|
||||
echo '<strong>public.tbl_notizzuordnung: '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo '<br>public.tbl_notizzuordnung: eindeutige_kalender_gruppen_id column added';
|
||||
}
|
||||
@@ -61059,6 +61059,86 @@ I have been informed that I am under no obligation to consent to the transmissio
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'tags_assignment_modal_title',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Tag-Zuweisung',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Tag Assignment',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'assigned_tags_subtitle',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Zugewiesene Tags',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Assigned Tags',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'no_assigned_tags',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Keine zugewiesenen Tags',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'No Assigned Tags',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'tags',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Tags',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Tags',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
// generic tabulator phrases END
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user