- Listenansicht hoehe der Tabelle auf 100%

- Listenansicht "status" Delete entfernt, Button gelassen
- Tags ohne Dialog & Popaus aus dem Kontextmenue entfernt
- Einstellung Prioraum verwenden Raumauswahl anzeigen als Dropdown
- Sortierung der Raeume im Event
- Reservierung anzeigen wenn STG Filter gesetzt ist
- Course Picker kuerzen von Events erst nach Confirm
- Fehlende Phrasen hinzugefuegt
This commit is contained in:
ma0048
2026-10-06 12:53:40 +02:00
parent 17e5d59efa
commit 6ae321280e
15 changed files with 357 additions and 200 deletions
@@ -39,8 +39,7 @@ class Config extends FHCAPI_Controller
'ignore_zeitsperre',
'ignore_resources_collisions',
'roomless_planning',
'priority_room_planning',
'dialog_room_planning'
'room_planning',
);
$result = $this->_ci->VariableModel->getVariables(getAuthUID(), $var_array);
@@ -49,7 +48,6 @@ class Config extends FHCAPI_Controller
"type" => "checkbox",
"label" => $this->p->t('ui', 'ignore_kollision'),
"value" => ($data['ignore_kollision'] ?? 'false') === 'true'
];
$config['kollision_student'] = [
@@ -83,19 +81,16 @@ class Config extends FHCAPI_Controller
"value" => ($data['roomless_planning'] ?? 'false') === 'true'
];
$config['priority_room_planning'] = [
"type" => "checkbox",
"label" => $this->p->t('ui', 'priority_room_planning'),
"value" => ($data['priority_room_planning'] ?? 'false') === 'true'
$config['room_planning'] = [
"type" => "select",
"label" => $this->p->t('ui', 'room_planning'),
"value" => $data['room_planning'] ?? "dialog_room_planning",
"options" => [
'dialog_room_planning' => $this->p->t('ui', 'dialog_room_planning'),
'priority_room_planning' => $this->p->t('ui', 'priority_room_planning'),
],
];
$config['dialog_room_planning'] = [
"type" => "checkbox",
"label" => $this->p->t('ui', 'dialog_room_planning'),
"value" => ($data['dialog_room_planning'] ?? 'false') === 'true'
];
$this->terminateWithSuccess($config);
}
public function getHeader()
@@ -121,6 +116,8 @@ class Config extends FHCAPI_Controller
public function set()
{
$this->_ci->load->library('form_validation');
$configs = array(
'ignore_kollision',
'kollision_student',
@@ -128,10 +125,18 @@ class Config extends FHCAPI_Controller
'ignore_zeitsperre',
'ignore_resources_collisions',
'roomless_planning',
'priority_room_planning',
'dialog_room_planning'
);
$this->form_validation->set_rules(
'room_planning',
$this->p->t('ui', 'room_planning'),
'required|in_list[dialog_room_planning,priority_room_planning]'
);
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
foreach ($configs as $config)
{
$this->_ci->VariableModel->setVariable(
@@ -141,6 +146,12 @@ class Config extends FHCAPI_Controller
);
}
$this->VariableModel->setVariable(
getAuthUID(),
'room_planning',
$this->input->post('room_planning')
);
$this->terminateWithSuccess();
}
@@ -457,7 +457,8 @@ class Kalender extends FHCAPI_Controller
$ort_kurzbz = $this->_ci->input->post('ort_kurzbz', TRUE);
$start_date = $this->_ci->input->post('start_date', TRUE);
$end_date = $this->_ci->input->post('end_date', TRUE);
$result = $this->_ci->kalenderlib->addKalenderEvent($start_date, $end_date, $lehreinheit_id, $ort_kurzbz);
$first_run = $this->_ci->input->post('first_run', TRUE) ?? true;
$result = $this->_ci->kalenderlib->addKalenderEvent($start_date, $end_date, $lehreinheit_id, $ort_kurzbz, $first_run);
if (isError($result))
$this->terminateWithError(getError($result));
@@ -138,6 +138,12 @@ class Reservierung extends FHCAPI_Controller
return in_array($gruppe->studiengang_kz, $stg_berechtigungen);
});
usort($gefilterte_gruppen, function ($a, $b)
{
return [(int) $a->semester, $a->gruppe_kurzbz] <=> [(int) $b->semester, $b->gruppe_kurzbz];
});
$this->terminateWithSuccess($gefilterte_gruppen);
}
+91 -37
View File
@@ -50,7 +50,6 @@ class KalenderLib
public function getForRaumvorschlag($start_date, $end_date, $lektor_uids = [], $gruppen_kurzbz = [], $lehrverband_gruppen = [])
{
$start_date = date('Y-m-d', strtotime($start_date));
$end_date = date('Y-m-d', strtotime($end_date . ' +1 day'));
$this->_buildBasePlanQuery();
@@ -169,23 +168,38 @@ class KalenderLib
if (!is_null($studiengaenge))
{
$db = $this->_ci->KalenderModel->db;
$or_conditions = array();
$lv_or_conditions = array();
$teilnehmer_or_conditions = array();
foreach ($studiengaenge as $studiengang)
{
$conditions = array();
$conditions[] = 'filter_lv.studiengang_kz = ' . $db->escape($studiengang['stg_kz']);
$stg_kz = $db->escape($studiengang['stg_kz']);
$lv_conditions = array('filter_lv.studiengang_kz = '. $stg_kz);
$teilnehmer_conditions = array('COALESCE(filter_teilnehmer.studiengang_kz, filter_grp.studiengang_kz) = ' .$stg_kz);
if (isset($studiengang['semester']))
$conditions[] = 'filter_lv.semester = ' . $db->escape($studiengang['semester']);
{
$semester = $db->escape($studiengang['semester']);
$lv_conditions[] = 'filter_lv.semester = ' . $semester;
$teilnehmer_conditions[] = 'COALESCE(filter_teilnehmer.semester, filter_grp.semester) = ' . $semester;
}
if (isset($studiengang['orgform_kurzbz']))
$conditions[] = 'filter_lv.orgform_kurzbz = ' . $db->escape($studiengang['orgform_kurzbz']);
{
$orgform_kurzbz = $db->escape($studiengang['orgform_kurzbz']);
$lv_conditions[] = 'filter_lv.orgform_kurzbz = ' . $orgform_kurzbz;
$teilnehmer_conditions[] = 'COALESCE(filter_lehrverband.orgform_kurzbz, filter_grp.orgform_kurzbz) = ' . $orgform_kurzbz;
}
$or_conditions[] = '(' . implode(' AND ', $conditions) . ')';
$lv_or_conditions[] = '(' . implode(' AND ', $lv_conditions) . ')';
$teilnehmer_or_conditions[] = '(' . implode(' AND ', $teilnehmer_conditions) . ')';
}
$or_block = implode(' OR ', $or_conditions);
$lv_or_block = implode(' OR ', $lv_or_conditions);
$teilnehmer_or_block = implode(' OR ', $teilnehmer_or_conditions);
$this->_ci->KalenderModel->db->where(
"(EXISTS (
@@ -194,8 +208,20 @@ class KalenderLib
JOIN lehre.tbl_lehreinheit filter_le ON filter_le.lehreinheit_id = filter_kl.lehreinheit_id
JOIN lehre.tbl_lehrveranstaltung filter_lv ON filter_lv.lehrveranstaltung_id = filter_le.lehrveranstaltung_id
WHERE filter_kl.kalender_id = tbl_kalender.kalender_id
AND ($or_block)
))"
AND ($lv_or_block)
)
OR EXISTS (
SELECT 1
FROM lehre.tbl_kalender_event_teilnehmer filter_teilnehmer
LEFT JOIN public.tbl_gruppe filter_grp ON filter_grp.gruppe_kurzbz = filter_teilnehmer.gruppe_kurzbz
LEFT JOIN public.tbl_lehrverband filter_lehrverband ON filter_lehrverband.studiengang_kz = filter_teilnehmer.studiengang_kz
AND filter_lehrverband.semester = filter_teilnehmer.semester
AND TRIM(COALESCE(filter_teilnehmer.verband::text, '')) = TRIM(filter_lehrverband.verband::text)
AND TRIM(COALESCE(filter_teilnehmer.gruppe::text, '')) = TRIM(filter_lehrverband.gruppe::text)
WHERE filter_teilnehmer.kalender_id = tbl_kalender.kalender_id
AND (filter_teilnehmer.gruppe_kurzbz IS NOT NULL OR filter_teilnehmer.studiengang_kz IS NOT NULL)
AND ($teilnehmer_or_block)
))", null, false
);
}
@@ -537,6 +563,11 @@ class KalenderLib
'false'
);
$this->_ci->StundeModel->addLimit(1);
$this->_ci->StundeModel->addOrder('stunde', 'DESC');
$letzte_stunde_result = $this->_ci->StundeModel->load();
$letzte_stunde = getData($letzte_stunde_result)[0];
while ($rest > 0 && new DateTime($current_date) < $ende)
{
$max_skip = 52;
@@ -564,12 +595,7 @@ class KalenderLib
if (!hasData($end_stunde_result))
{
$errors[] = [
'datum' => $current_date,
'message' => 'Endzeit entspricht keinem gültigen Raster',
];
$current_date = $this->_addWeeks($current_date, $wochenrythmus);
continue;
$current_block = $letzte_stunde->stunde - $start_stunde_nr + 1;
}
$end_time = getData($end_stunde_result)[0]->ende;
@@ -655,7 +681,7 @@ class KalenderLib
}
public function addKalenderEvent($start_date, $end_date, $lehreinheit_id, $ort_kurzbz)
public function addKalenderEvent($start_date, $end_date, $lehreinheit_id, $ort_kurzbz, $first_run = false)
{
if (!$this->_checkPermission((array)$lehreinheit_id))
{
@@ -674,24 +700,45 @@ class KalenderLib
$raum_vorschlaege = $this->_ci->raumvorschlaglib->getVorschlaegeByLehreinheit($lehreinheit_id, $start_date, $end_date);
if (($this->_ci->variablelib->getVar('dialog_room_planning') ?? 'false') === 'true')
$room_planning = $this->_ci->variablelib->getVar('room_planning') ?? 'priority_room_planning';
if ($first_run || (($this->_ci->variablelib->getVar('roomless_planning') ?? 'false') !== 'true'))
{
return success([
'needs_room_selection' => true,
'raum_vorschlaege' => is_array($raum_vorschlaege) ? $raum_vorschlaege : [],
]);
}
if ($room_planning === 'dialog_room_planning')
{
if (!$first_run)
{
return error([
'message' => $this->_ci->phraseslib->t('ui', 'roomless_planning_error'),
'errorCode' => 'roomless_planning_error'
]);
}
else
{
return success([
'needs_room_selection' => true,
'raum_vorschlaege' => is_array($raum_vorschlaege) ? $raum_vorschlaege : [],
]);
}
}
else if ($room_planning === 'priority_room_planning')
{
$ort_kurzbz = !empty($raum_vorschlaege[0]['ort_kurzbz']) ? $raum_vorschlaege[0]['ort_kurzbz'] : null;
if (($this->_ci->variablelib->getVar('priority_room_planning') ?? 'false') === 'true')
{
$ort_kurzbz = (is_array($raum_vorschlaege)) ? $raum_vorschlaege[0]['ort_kurzbz'] : null;
}
else if (!(($this->_ci->variablelib->getVar('roomless_planning') ?? 'false') === 'true'))
{
return error([
'message' => $this->_ci->phraseslib->t('ui', 'roomless_planning_error'),
'errorCode' => 'roomless_planning_error'
]);
if (is_null($ort_kurzbz) && !(($this->_ci->variablelib->getVar('roomless_planning') ?? 'false') === 'true'))
{
return error([
'message' => $this->_ci->phraseslib->t('ui', 'roomless_prio_planning_error'),
'errorCode' => 'roomless_planning_error'
]);
}
}
else if (!(($this->_ci->variablelib->getVar('roomless_planning') ?? 'false') === 'true'))
{
return error([
'message' => $this->_ci->phraseslib->t('ui', 'roomless_planning_error'),
'errorCode' => 'roomless_planning_error'
]);
}
}
}
@@ -901,7 +948,7 @@ class KalenderLib
if (!empty($errors)) {
return error($errors);
}
$this->_ci->db->trans_start();
$allowedResourceIDs = array_filter(array_map(
@@ -984,7 +1031,7 @@ class KalenderLib
if (!is_null($orte))
{
$kalender_entry->ort_kurbz = !isEmptyArray($orte['ort_kurzbz'] ?? null) ? (array) $orte['ort_kurzbz'] : $kalender_entry->ort_kurzbz;
$kalender_entry->ort_kurzbz = !isEmptyArray($orte['ort_kurzbz'] ?? null) ? (array) $orte['ort_kurzbz'] : $kalender_entry->ort_kurzbz;
$kalender_entry->location = array_key_exists('location', $orte) && !is_null($orte['location']) ? $orte['location'] : $kalender_entry->location;
}
$kalender_entry->von = $start_time ?? $kalender_entry->von;
@@ -1657,7 +1704,7 @@ class KalenderLib
if ($row->verband_grp)
{
if (!in_array($row->teilnehmerg_grp, array_column($events[$id]->teilnehmer_gruppe, 'gruppe_kurzbz')))
if (!in_array($row->verband_grp, array_column($events[$id]->teilnehmer_gruppe, 'gruppe_kurzbz')))
{
$events[$id]->teilnehmer_gruppe[] = [
'gruppe_kurzbz' => $row->verband_grp,
@@ -1718,6 +1765,11 @@ class KalenderLib
}
}
foreach ($events as $event)
{
usort($event->ort_kurzbz, 'strnatcasecmp');
}
return array_values($events);
}
@@ -1753,6 +1805,8 @@ class KalenderLib
if (hasData($ferien_result))
return true;
return false;
}
private function _insertKalenderEventRaw($start_date, $end_date, $lehreinheit_id, $ort_kurzbz)
@@ -2140,7 +2194,7 @@ class KalenderLib
$lehreinheit = $this->_ci->LehreinheitModel->load();
if (!hasData($lehreinheit))
return error('Lehreinheit nicht gefunden');
return false;
$studiengaenge = array_unique(array_column(getData($lehreinheit), 'studiengang_kz'));
+2 -2
View File
@@ -96,11 +96,11 @@ export default {
params: { kalender_id}
};
},
addKalenderEvent(lehreinheit_id, ort_kurzbz, start_date, end_date) {
addKalenderEvent(lehreinheit_id, ort_kurzbz, start_date, end_date, first_run) {
return {
method: 'post',
url: '/api/frontend/v1/tempus/Kalender/addKalenderEvent',
params: { lehreinheit_id, ort_kurzbz, start_date, end_date}
params: { lehreinheit_id, ort_kurzbz, start_date, end_date, first_run}
};
},
calculateMultiWeekPlan(lehreinheit_id, ort_kurzbz, start_date, end_date) {
+16 -6
View File
@@ -383,12 +383,12 @@ export default {
if (accumulated >= duration)
{
const overflow = accumulated.minus(duration);
return blockEnd.minus(overflow);
return {end: blockEnd.minus(overflow), shortened: false}
}
}
const lastBlock = blocks[blocks.length - 1];
return dropStart.startOf('day').plus(lastBlock.end);
return {end: dropStart.startOf('day').plus(lastBlock.end), shortened: true}
},
onDropEvent(evt, items, date)
@@ -398,7 +398,7 @@ export default {
else
this.onDropFree(evt, items, date)
},
onDropSnap(evt, items, date, part) {
async onDropSnap(evt, items, date, part) {
let obj = items;
if (!obj?.orig) return;
@@ -419,7 +419,13 @@ export default {
const dropStart = snappedPart ? dropDay.plus(snappedPart.start) : grabTime;
let nettoDuration = this._getNettoDurationForDrop(obj);
let dropEnd = this.calculateDropEnd(dropStart, nettoDuration);
let {end: dropEnd, shortened} = this.calculateDropEnd(dropStart, nettoDuration);
if (shortened && await this.$fhcAlert.confirm({message: 'Wird auf ' + dropEnd.toFormat('HH:mm') + ' gekürzt. Fortfahren?'}) === false)
{
return;
}
this.onDrop?.({
item: [obj],
@@ -449,7 +455,7 @@ export default {
return luxon.Duration.fromObject({ minutes: 45 });
},
onDropFree(evt, items, date)
async onDropFree(evt, items, date)
{
let obj = items;
if (!obj?.orig)
@@ -459,8 +465,12 @@ export default {
const dropStart = luxon.DateTime.fromMillis(timestamp);
let nettoDuration = this._getNettoDurationForDrop(obj);
let dropEnd = this.calculateDropEnd(dropStart, nettoDuration);
let {end: dropEnd, shortened} = this.calculateDropEnd(dropStart, nettoDuration);
if (shortened && await this.$fhcAlert.confirm({message: 'Wird auf ' + dropEnd.toFormat('HH:mm') + ' gekürzt. Fortfahren?'}) === false)
{
return;
}
this.onDrop?.({
item: [obj],
start: dropStart.toISO(),
+2 -1
View File
@@ -48,7 +48,8 @@ export default {
this.$emit('update:range', this.range);
},
template: `
<div>
<div
class="fhc-calendar-mode-month flex-grow-1 position-relative">
<table-view ref="view" v-bind="$attrs" :day="focusDate" :end="focusEnd">
<template v-slot="slot"><slot v-bind="slot" mode="week" /></template>
</table-view>
@@ -85,6 +85,7 @@ export default {
layout: 'fitDataStretch',
placeholder: "Keine Daten verfügbar",
persistenceID: "2026_09_29_table_view_v1",
height: '100%',
data: this.preparedEvents,
columns: [
{
@@ -132,11 +133,10 @@ export default {
let semester = cell.getRow().getData().le_studiensemester_kurzbz.toLowerCase();
let base_url = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
//TODO (david) abhängig von der LVVerwaltung
/*return value.map(lehreinheit => {
return value.map(lehreinheit => {
let url = `${base_url}/LVVerwaltung/stdsem/${semester}/le/${lehreinheit}`;
return `<a href="${url}" target="_blank">${lehreinheit}</a>`;
}).join(', ');*/
}).join(', ');
},
},
{
@@ -352,7 +352,7 @@ export default {
},
},
template: /* html */`
<div class="fhc-calendar-mode-table-view h-100 overflow-auto">
<div class="fhc-calendar-mode-table-view position-absolute top-0 start-0 w-100 h-100 d-flex flex-column">
<core-filter-cmpt
ref="tableViewTable"
:tabulator-options="tabulatorOptions"
@@ -380,7 +380,6 @@ export default {
<div class="d-flex gap-2 align-items-baseline">
<select v-model="actionSelect" class="form-select">
<option selected disabled value="">Status setzen</option>
<option value="delete">Löschen</option>
<option value="toLecturer">Freischalten für Voransicht</option>
<option value="toStudent">Freischalten für Live</option>
</select>
@@ -1,13 +1,15 @@
import TagsAssignmentModal from "../../TagsAssignmentModal.js";
import ApiKalender from '../../../../api/factory/tempus/kalender.js';
import FormInput from "../../../Form/Input.js";
import RaumauswahlModal from '../../RaumauswahlModal.js';
import CoreTag from '../../../../components/Tag/Tag.js';
import ApiTempusTag from "../../../../api/factory/tempus/tag.js";
import { idTagFormatter } from "../../../Tag/tagFormatter.js";
export default {
components:{
FormInput,
TagsAssignmentModal,
RaumauswahlModal
RaumauswahlModal,
CoreTag
},
props:{
event: {
@@ -46,7 +48,8 @@ export default {
anzahl: '',
anzahlSchwund: '',
mailto: '',
zeitwunschMap: {}
zeitwunschMap: {},
tagEndpoint: ApiTempusTag,
};
},
watch: {
@@ -54,9 +57,17 @@ export default {
if (this.editStundeBis !== null && this.editStundeBis < newVal)
this.editStundeBis = newVal;
},
tags: {
handler() {
this.renderTags();
},
deep: true
}
},
computed: {
tagValues() {
return this.event.eindeutige_kalender_gruppen_id ? [this.event.eindeutige_kalender_gruppen_id] : [];
},
lektorenLinks: function () {
if (!this.event || !Array.isArray(this.event.lektor) || !this.event.lektor.length) return "a";
@@ -66,14 +77,8 @@ export default {
})
return lektorenLinks;
},
getOrtContentLink: function () {
if (!this.event || !this.event.ort_content_id) return "a";
return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + `/CisVue/Cms/content/${this.event.ort_content_id}`
},
lvLinks()
{
//TODO (david) abhängig von der LVVerwaltung
let semester = this.event.le_studiensemester_kurzbz.toLowerCase();
let base_url = FHC_JS_DATA_STORAGE_OBJECT.app_root;
let ci_url = base_url + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
@@ -82,26 +87,22 @@ export default {
lvverwaltung: {},
vilesci: {},
}
/*this.event.lehrveranstaltung_infos.forEach(lehrveranstaltung => {
this.event.lehrveranstaltung_infos.forEach(lehrveranstaltung => {
lvLinks.lvverwaltung[lehrveranstaltung.lehrveranstaltung_id] = `${ci_url}/LVVerwaltung/stdsem/${semester}/lv/${lehrveranstaltung.lehrveranstaltung_id}`;
lvLinks.vilesci[lehrveranstaltung.lehrveranstaltung_id] = `${base_url}vilesci/lehre/lehrveranstaltung_details.php?lv_id=${lehrveranstaltung.lehrveranstaltung_id}`;
})*/
})
return lvLinks;
},
leLinks()
{
//TODO (david) abhängig von der LVVerwaltung
let base_url = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
let leLinks = {};
/* this.event.lehreinheit_infos.forEach(lehreinheit => {
this.event.lehreinheit_infos.forEach(lehreinheit => {
leLinks[lehreinheit.lehreinheit_id] = `${base_url}/LVVerwaltung/stdsem/${lehreinheit.studiensemester_kurzbz}/le/${lehreinheit.lehreinheit_id}`;
})*/
})
return leLinks;
},
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 {
@@ -181,9 +182,27 @@ export default {
this.modalActions.saveEventTime({kalender_id: this.event.kalender_id, start_time, end_time});
},
async openTagsModal(tag = null)
{
await this.$refs.tagsModal.open(this.event, tag);
async fetchAssignedTagsByCalender(calendarGroupId) {
let result = await this.$api.call(
ApiTempusTag.getTagsByCalendar(calendarGroupId),
);
if (result.meta.status === "success")
return result.data.filter(tag => !!tag);
this.$fhcAlert.alertError(
this.$p.t("ui", "failed_assigned_tags_fetch_error_message"),
);
return [];
},
async onTagsChanged() {
let id = this.event.eindeutige_kalender_gruppen_id;
if (!id) return;
this.event.tags = await this.fetchAssignedTagsByCalender(id);
},
editTag(tag) {
this.$refs.tagComponent?.editTag(tag.id);
},
openRaumvorschlag()
{
@@ -200,6 +219,26 @@ export default {
ort_kurzbz: room,
}, 'ort');
},
renderTags()
{
let el = this.$refs.tagWrapper;
if (!el) return;
const tagData = this.tags.map(t => ({
...t,
notiz_id: t.id,
bezeichnung: t.beschreibung,
}));
el.replaceChildren(
idTagFormatter(
this.event.eindeutige_kalender_gruppen_id,
tagData,
this.$refs.tagComponent,
'eindeutige_kalender_gruppen_id'
) ?? ''
);
}
},
created() {
if (this.event.type == 'lehreinheit') {
@@ -214,6 +253,10 @@ export default {
})
}
},
mounted()
{
this.renderTags();
},
template: /*html*/`
<div>
<h5>
@@ -223,7 +266,7 @@ export default {
<tbody>
<tr v-if="this.event.collisions.length > 0">
<th><i class="fa-solid fa-triangle-exclamation text-danger"></i> {{ $p.t('ui','collision') }}</th>
<th><i class="fa-solid fa-triangle-exclamation text-danger"></i> {{ $p.t('ui','collision') }}:</th>
<td>
<div v-for="collision in this.event.collisions" class="d-block">
{{collision.message}}
@@ -231,13 +274,8 @@ export default {
</td>
</tr>
<tr>
<th>{{
$p.t('global','datum')?
$p.t('global','datum')+':'
:''
}}</th>
<td>
<th>{{$p.t('global','datum')+':'}}</th>
<td>
<form-input
ref="editDatumInput"
type="DatePicker"
@@ -254,11 +292,7 @@ export default {
</td>
</tr>
<tr>
<th>{{
$p.t('ui','zeitraum')?
$p.t('ui','zeitraum')+':'
:''
}}</th>
<th>{{$p.t('ui','zeitraum')+':'}}</th>
<td>
<template v-if="showRaster">
<select v-model="editStundeVon" class="form-select form-select-sm w-auto d-inline-block">
@@ -308,7 +342,7 @@ export default {
</td>
</tr>
<tr>
<th>{{$p.t('global','raum')}}
<th>{{$p.t('global','raum')}}:
<i
class="fa-solid fa-refresh"
@click="openRaumvorschlag"
@@ -323,7 +357,7 @@ export default {
</tr>
<tr>
<th>{{$p.t('global','anzahl')}} {{$p.t('global','students')}}
<th>{{$p.t('global','anzahl')}} {{$p.t('global','students')}}:
</th>
<td>
{{anzahlSchwund}} ({{anzahl}})
@@ -376,40 +410,36 @@ export default {
</td>
</tr>
<tr v-if="resourcesValue">
<th>{{
$p.t('ui','betriebsmittel')?
$p.t('ui','betriebsmittel')+':'
:''
}}</th>
<th>{{$p.t('ui','betriebsmittel') + ':'}}</th>
<td>
{{ resourcesValue }}
</td>
</tr>
<tr>
<th>{{
$p.t('ui','tags')?
$p.t('ui','tags')+':'
:''
}} <i
class="fa-solid fa-tags"
@click="openTagsModal(null)"
></i>
<th>
<div class="d-flex align-items-center flex-wrap">
{{$p.t('ui','tags')}}:
<div class="fw-normal">
<core-tag
v-if="tagValues.length"
ref="tagComponent"
:endpoint="tagEndpoint"
:values="tagValues"
zuordnung_typ="eindeutige_kalender_gruppen_id"
show-hover
@added="onTagsChanged"
@deleted="onTagsChanged"
@updated="onTagsChanged"
></core-tag>
</div>
</div>
</th>
<td>
<div v-if="tags.length">
<span
v-for="tag in tags"
:key="tag.tag_typ_kurzbz"
:class="[tag.style, { tag_done: tag.done }]"
@click="openTagsModal(tag)"
class="tag disabled"
>{{ tag.beschreibung }}</span>
</div>
<div ref="tagWrapper"></div>
</td>
</tr>
<tr>
<th>{{$p.t('lehre','mail')}} </th>
<th>{{$p.t('lehre','mail')}}: </th>
<td>
<a class="fhc-link-color" :href="'mailto:' + mailto">
<i class="fa-solid fa-envelope"></i>
@@ -418,7 +448,6 @@ export default {
</tr>
</tbody>
</table>
<tags-assignment-modal ref="tagsModal"/>
<raumauswahl-modal ref="raumModal" @saved="reload()"/>
<button type="button" class="btn btn-primary " @click.stop="onSave">{{$p.t('ui', 'speichern')}}</button>
</div>`,
@@ -1,6 +1,6 @@
import { numberPadding, formatDate } from "../../../../helpers/DateHelpers.js"
import LvMenu from "../../../Cis/Mylv/LvMenu.js";
import TagsAssignmentModal from "../../TagsAssignmentModal.js";
import ApiTempusTag from "../../../../api/factory/tempus/tag.js";
import CoreTag from '../../../../components/Tag/Tag.js';
export default {
props:{
@@ -8,17 +8,20 @@ export default {
type: Object,
required: true,
},
lvMenu:{
type: Object,
required: false,
default: null,
},
},
components:{
LvMenu,
TagsAssignmentModal
components: {
CoreTag
},
data()
{
return {
tagEndpoint: ApiTempusTag
}
},
computed: {
tagValues() {
return this.event.eindeutige_kalender_gruppen_id ? [this.event.eindeutige_kalender_gruppen_id] : [];
},
lektorenLinks: function () {
if (!this.event || !Array.isArray(this.event.lektor) || !this.event.lektor.length) return "a";
@@ -69,9 +72,27 @@ export default {
methodFormatDate: function (d) {
return formatDate(d);
},
async openTagsModal(tag = null)
{
await this.$refs.tagsModal.open(this.event, tag);
async fetchAssignedTagsByCalender(calendarGroupId) {
let result = await this.$api.call(
ApiTempusTag.getTagsByCalendar(calendarGroupId),
);
if (result.meta.status === "success")
return result.data.filter(tag => !!tag);
this.$fhcAlert.alertError(
this.$p.t("ui", "failed_assigned_tags_fetch_error_message"),
);
return [];
},
async onTagsChanged() {
let id = this.event.eindeutige_kalender_gruppen_id;
if (!id) return;
this.event.tags = await this.fetchAssignedTagsByCalender(id);
},
editTag(tag) {
this.$refs.tagComponent?.editTag(tag.id);
},
},
template: `
@@ -129,11 +150,7 @@ export default {
</tr>
<tr>
<th>{{
$p.t('ui','teilnehmende')?
$p.t('ui','teilnehmende')+':'
:''
}}</th>
<th>{{$p.t('ui','teilnehmende')+':'}}</th>
<td>
<div v-for="teilnehmer in event.teilnehmer_person" class="d-block">
{{teilnehmer.kurzbz}}
@@ -144,33 +161,38 @@ export default {
</td>
</tr>
<tr>
<th>{{
$p.t('ui','tags')?
$p.t('ui','tags')+':'
:''
}} <i
class="fa-solid fa-tags"
@click="openTagsModal(null)"
></i>
<th>
<div class="d-flex align-items-center flex-wrap">
{{$p.t('ui','tags')}}:
<div class="fw-normal">
<core-tag
v-if="tagValues.length"
ref="tagComponent"
:endpoint="tagEndpoint"
:values="tagValues"
zuordnung_typ="eindeutige_kalender_gruppen_id"
show-hover
@added="onTagsChanged"
@deleted="onTagsChanged"
@updated="onTagsChanged"
></core-tag>
</div>
</div>
</th>
<td>
<div v-if="tags.length">
<span
v-for="tag in tags"
:key="tag.tag_typ_kurzbz"
:class="[tag.style, { tag_done: tag.done }]"
@click="openTagsModal(tag)"
class="tag disabled"
>{{ tag.beschreibung }}</span>
</div>
<span
v-for="tag in tags"
:key="tag.id"
:class="[tag.style, { tag_done: tag.done }]"
@click="editTag(tag)"
class="tag"
>{{ tag.beschreibung }}</span>
</td>
</tr>
</tbody>
</table>
<tags-assignment-modal ref="tagsModal"/>
</div>`,
}
@@ -31,21 +31,6 @@ export default {
},
},
methods: {
async open(calendar, tagToEdit = null) {
if (!calendar?.eindeutige_kalender_gruppen_id) return;
this.calendar = calendar;
this.availableTags = await this.fetchAvailableTags();
this.filteredAvailableTags = [...this.dropdownParsedAvailableTags];
this.assignedTags = await this.fetchAssignedTagsByCalender(
calendar.eindeutige_kalender_gruppen_id,
);
this.show();
if (tagToEdit)
this.editTag(tagToEdit);
},
show() {
this.$refs.modal.show();
},
-4
View File
@@ -29,7 +29,6 @@ import { useContextMenuActions } from '../../composables/Tempus/ContextMenuActio
import MultiWeekPlanModal from './MultiWeekPlanModal.js';
import HistoryModal from './HistoryModal.js';
import ResourcesAssignmentModal from './ResourcesAssignmentModal.js';
import TagsAssignmentModal from './TagsAssignmentModal.js';
import { getTempusSearchbarOptions } from './Filters/searchbarOptions.js';
import TempusHeader from './Header.js';
import TempusAppMenu from './AppMenu.js';
@@ -54,7 +53,6 @@ export default {
MultiWeekPlanModal,
HistoryModal,
ResourcesAssignmentModal,
TagsAssignmentModal,
RaumauswahlModal,
RaumauswahlMultiModal,
LehreinheitModal,
@@ -85,7 +83,6 @@ export default {
openRaumauswahl: (orig) => this.$refs.raumModal.show(orig),
openLehreinheit: (orig) => this.$refs.lehreinheitModal.show(orig),
openResourcesAssignmentModal: (orig) => this.$refs.resourcesAssignmentModal?.open(orig),
openTagsModal: (orig) => this.$refs.tagsAssignmentModal?.open(orig),
openHistory: (orig) => this.openHistory(orig),
deleteEntry: (orig) => this.deleteEntry(orig),
syncToLecturer: (orig) => this.syncToLecturer(orig),
@@ -1066,7 +1063,6 @@ export default {
ref="resourcesAssignmentModal"
@save-finished="$refs.calendar.resetEventLoader()"
/>
<tags-assignment-modal ref="tagsAssignmentModal"/>
<history-modal ref="historyModal" :entries="historyEntries" />
<reservierung
ref="reservierung"
@@ -18,11 +18,6 @@ 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',
@@ -52,11 +47,6 @@ export function useContextMenuActions(handlers)
icon: 'fa-solid fa-door-open',
action: handlers.openRaumauswahl
},
{
label: 'Tags',
icon: 'fa-solid fa-tags',
action: handlers.openTagsModal
},
{
label: 'Delete',
icon: 'fa-solid fa-calendar-xmark',
@@ -5,13 +5,26 @@ if ($result = @$db->db_query("SELECT 1 FROM public.tbl_variablenname WHERE name
{
if ($db->db_num_rows($result) == 0)
{
$qry = "INSERT INTO public.tbl_variablenname(name, defaultwert) VALUES('roomless_planning', false);
INSERT INTO public.tbl_variablenname(name, defaultwert) VALUES('priority_room_planning', false);
INSERT INTO public.tbl_variablenname(name, defaultwert) VALUES('dialog_room_planning', false);";
$qry = "INSERT INTO public.tbl_variablenname(name, defaultwert) VALUES('roomless_planning', false);";
if (!$db->db_query($qry))
echo '<strong>public.tbl_variablenname '.$db->db_last_error().'</strong><br>';
else
echo 'public.tbl_variablenname: Added "roomless_planning", "priority_room_planning", "dialog_room_planning"<br>';
echo 'public.tbl_variablenname: Added "roomless_planning"<br>';
}
}
if ($result = @$db->db_query("SELECT 1 FROM public.tbl_variablenname WHERE name = 'room_planning';"))
{
if ($db->db_num_rows($result) == 0)
{
$qry = "INSERT INTO public.tbl_variablenname(name, defaultwert) VALUES('room_planning', null);
DELETE FROM public.tbl_variable WHERE name IN('priority_room_planning', 'dialog_room_planning');
DELETE FROM public.tbl_variablenname WHERE name IN('priority_room_planning', 'dialog_room_planning');";
if (!$db->db_query($qry))
echo '<strong>public.tbl_variablenname '.$db->db_last_error().'</strong><br>';
else
echo 'public.tbl_variablenname: Added "room_planning"<br>';
}
}
+40
View File
@@ -37625,6 +37625,46 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'roomless_prio_planning_error',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Prioritätsraum nicht gefunden und raumlose Planung deaktiviert',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Priority room not found and roomless planning is disabled.',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'room_planning',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Raumlplanung',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Room planning',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',