mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-19 16:02:15 +00:00
- wording angepasst lehreinheit -> lvteil
- Kollisionscheck an/aus wird angezeigt - Shortcut für Ignore-Collision (F9) hinzugefuegt - coursepicker: - design angepasst - favorisieren ermoeglicht - phrases - bei lv immer alle raeume/lektoren/gruppen anzeigen unabhaengig vom filter
This commit is contained in:
@@ -14,6 +14,7 @@ class Config extends FHCAPI_Controller
|
||||
'get' => ['admin:r', 'assistenz:r'],
|
||||
'getHeader' => ['admin:r', 'assistenz:r'],
|
||||
'set' => ['admin:r', 'assistenz:r'],
|
||||
'updateCollision' => ['admin:r', 'assistenz:r'],
|
||||
]);
|
||||
|
||||
// Load Phrases
|
||||
@@ -23,12 +24,12 @@ class Config extends FHCAPI_Controller
|
||||
|
||||
$this->_ci = &get_instance();
|
||||
$this->_ci->load->model('ressource/Kalenderstatus_model', 'KalenderStatusModel');
|
||||
$this->_ci->load->model('system/Variable_model', 'VariableModel');
|
||||
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
|
||||
}
|
||||
|
||||
public function get()
|
||||
{
|
||||
$this->_ci->load->model('system/Variable_model', 'VariableModel');
|
||||
|
||||
$config = [];
|
||||
|
||||
$result = $this->_ci->VariableModel->getVariables(getAuthUID(), ['ignore_kollision', 'kollision_student', 'ignore_reservierung', 'ignore_zeitsperre']);
|
||||
@@ -87,8 +88,6 @@ class Config extends FHCAPI_Controller
|
||||
|
||||
public function set()
|
||||
{
|
||||
$this->_ci->load->model('system/Variable_model', 'VariableModel');
|
||||
|
||||
$this->_ci->VariableModel->setVariable(
|
||||
getAuthUID(),
|
||||
'ignore_kollision',
|
||||
@@ -112,5 +111,14 @@ class Config extends FHCAPI_Controller
|
||||
$this->terminateWithSuccess();
|
||||
}
|
||||
|
||||
public function updateCollision()
|
||||
{
|
||||
$original_ignore = $this->_ci->variablelib->getVar('ignore_kollision');
|
||||
$this->_ci->VariableModel->setVariable(
|
||||
getAuthUID(),
|
||||
'ignore_kollision',
|
||||
$original_ignore === 'true' ? 'false' : 'true'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ class Coursepicker extends FHCAPI_Controller
|
||||
'studiensemester_kurzbz' => $row->studiensemester_kurzbz,
|
||||
'fachbereich_kurzbz' => isset($row->fachbereich_kurzbz) ? $row->fachbereich_kurzbz : null,
|
||||
'lektoren' => array(),
|
||||
'lehreinheit_id' => array(),
|
||||
'lehreinheit_id' => $lehreinheit_id,
|
||||
'lvnr' => array(),
|
||||
'lehrfach' => array(),
|
||||
'lehrform' => array(),
|
||||
@@ -235,7 +235,6 @@ class Coursepicker extends FHCAPI_Controller
|
||||
'name' => $row->vorname . ' ' . $row->nachname,
|
||||
);
|
||||
|
||||
$group->lehreinheit_id[] = $row->lehreinheit_id;
|
||||
$group->lvnr[] = $row->lvnr;
|
||||
$group->lehrfach[] = $row->lehrfach;
|
||||
$group->lehrform[] = $row->lehrform;
|
||||
|
||||
@@ -344,43 +344,91 @@ class KalenderLib
|
||||
$this->_getBasePlan($start_date, $end_date);
|
||||
|
||||
if (!is_null($ort))
|
||||
$this->_ci->KalenderModel->db->where_in('tbl_kalender_ort.ort_kurzbz', $ort);
|
||||
{
|
||||
$ort_array = (array) $ort;
|
||||
$escaped_orte = array();
|
||||
|
||||
foreach ($ort_array as $ort)
|
||||
{
|
||||
$escaped_orte[] = $this->_ci->KalenderModel->db->escape($ort);
|
||||
}
|
||||
$in_list = '(' . implode(',', $escaped_orte) . ')';
|
||||
|
||||
$this->_ci->KalenderModel->db->where(
|
||||
"(EXISTS (
|
||||
SELECT 1
|
||||
FROM lehre.tbl_kalender_ort filter_ort
|
||||
WHERE filter_ort.kalender_id = tbl_kalender.kalender_id
|
||||
AND filter_ort.ort_kurzbz IN $in_list
|
||||
))"
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_null($uids))
|
||||
{
|
||||
$this->_ci->KalenderModel->db->group_start();
|
||||
$this->_ci->KalenderModel->db->where_in('tbl_lehreinheitmitarbeiter.mitarbeiter_uid', $uids);
|
||||
$this->_ci->KalenderModel->db->or_where_in('orginasator.uid', $uids);
|
||||
$this->_ci->KalenderModel->db->or_where_in('teilnehmer.uid', $uids);
|
||||
$this->_ci->KalenderModel->db->group_end();
|
||||
$uid_array = (array) $uids;
|
||||
$db = $this->_ci->KalenderModel->db;
|
||||
|
||||
$escaped_uids = array();
|
||||
foreach ($uid_array as $uid)
|
||||
$escaped_uids[] = $db->escape($uid);
|
||||
$in_list = '(' . implode(',', $escaped_uids) . ')';
|
||||
|
||||
$this->_ci->KalenderModel->db->where(
|
||||
"(EXISTS (
|
||||
SELECT 1
|
||||
FROM lehre.tbl_lehreinheitmitarbeiter filter_lem
|
||||
WHERE filter_lem.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
|
||||
AND filter_lem.mitarbeiter_uid IN $in_list
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1
|
||||
FROM lehre.tbl_kalender_event_teilnehmer filter_org
|
||||
WHERE filter_org.kalender_id = tbl_kalender.kalender_id
|
||||
AND filter_org.rolle_kurzbz = 'organisator'
|
||||
AND filter_org.uid IN $in_list
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1
|
||||
FROM lehre.tbl_kalender_event_teilnehmer filter_teil
|
||||
WHERE filter_teil.kalender_id = tbl_kalender.kalender_id
|
||||
AND filter_teil.rolle_kurzbz = 'teilnehmer'
|
||||
AND filter_teil.uid IN $in_list
|
||||
))"
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_null($studiengaenge))
|
||||
{
|
||||
$db = $this->_ci->KalenderModel->db;
|
||||
$or_conditions = array();
|
||||
|
||||
$this->_ci->KalenderModel->db->group_start();
|
||||
$first = true;
|
||||
foreach ($studiengaenge as $studiengang)
|
||||
{
|
||||
if ($first)
|
||||
$this->_ci->KalenderModel->db->group_start();
|
||||
else
|
||||
{
|
||||
$this->_ci->KalenderModel->db->or_group_start();
|
||||
}
|
||||
$first = false;
|
||||
|
||||
$this->_ci->KalenderModel->db->where('tbl_lehrveranstaltung.studiengang_kz', $studiengang['studiengang_kz']);
|
||||
$conditions = array();
|
||||
$conditions[] = 'filter_lv.studiengang_kz = ' . $db->escape($studiengang['studiengang_kz']);
|
||||
|
||||
if (isset($studiengang['semester']))
|
||||
$this->_ci->KalenderModel->db->where('tbl_lehrveranstaltung.semester', $studiengang['semester']);
|
||||
$conditions[] = 'filter_lv.semester = ' . $db->escape($studiengang['semester']);
|
||||
|
||||
if (isset($studiengang['orgform_kurzbz']))
|
||||
$this->_ci->KalenderModel->db->where('tbl_lehrveranstaltung.orgform_kurzbz', $studiengang['orgform_kurzbz']);
|
||||
$conditions[] = 'filter_lv.orgform_kurzbz = ' . $db->escape($studiengang['orgform_kurzbz']);
|
||||
|
||||
$this->_ci->KalenderModel->db->group_end();
|
||||
$or_conditions[] = '(' . implode(' AND ', $conditions) . ')';
|
||||
}
|
||||
$this->_ci->KalenderModel->db->group_end();
|
||||
|
||||
$or_block = implode(' OR ', $or_conditions);
|
||||
|
||||
$this->_ci->KalenderModel->db->where(
|
||||
"(EXISTS (
|
||||
SELECT 1
|
||||
FROM lehre.tbl_kalender_lehreinheit filter_kl
|
||||
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)
|
||||
))"
|
||||
);
|
||||
}
|
||||
|
||||
$this->_ci->KalenderModel->db->where('NOT EXISTS (
|
||||
|
||||
@@ -34,5 +34,11 @@ export default {
|
||||
url: 'api/frontend/v1/tempus/config/set',
|
||||
params
|
||||
};
|
||||
},
|
||||
updateCollision () {
|
||||
return {
|
||||
method: 'post',
|
||||
url: 'api/frontend/v1/tempus/config/updateCollision'
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -79,26 +79,30 @@ export default {
|
||||
this.$fhcAlert.alertSuccess(this.$p.t('ui/settings_saved'));
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemErrors);
|
||||
},
|
||||
reload()
|
||||
{
|
||||
this.$api
|
||||
.call(this.endpoints.get())
|
||||
.then(res => {
|
||||
Object.keys(res.data).forEach(key => {
|
||||
const binding = { ...res.data[key] };
|
||||
delete binding.value;
|
||||
delete binding.options;
|
||||
const options = res.data[key].options;
|
||||
this.tempValues[key] = res.data[key].value;
|
||||
this.setup[key] = {
|
||||
binding,
|
||||
options
|
||||
};
|
||||
});
|
||||
this.$emit('update:modelValue', { ...this.tempValues });
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemErrors);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$api
|
||||
.call(this.endpoints.get())
|
||||
.then(res => {
|
||||
Object.keys(res.data).forEach(key => {
|
||||
const binding = { ...res.data[key] };
|
||||
delete binding.value;
|
||||
delete binding.options;
|
||||
const options = res.data[key].options;
|
||||
this.tempValues[key] = res.data[key].value;
|
||||
this.setup[key] = {
|
||||
binding,
|
||||
options
|
||||
};
|
||||
});
|
||||
this.$emit('update:modelValue', { ...this.tempValues });
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemErrors);
|
||||
this.reload();
|
||||
},
|
||||
template: /* html */`
|
||||
<fhc-form class="stv-config" ref="form" @submit.prevent="update">
|
||||
|
||||
@@ -271,6 +271,12 @@ export default {
|
||||
></i>
|
||||
<span>Reservierung</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<i :class="appConfig.ignore_kollision ? 'fa-solid fa-triangle-exclamation text-danger' : 'fa-solid fa-circle-check text-success'"></i>
|
||||
<span class="form-check-label">
|
||||
{{ appConfig.ignore_kollision ? 'Kollisionscheck aus' : 'Kollisionscheck an' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</fhc-calendar>`
|
||||
|
||||
@@ -25,7 +25,8 @@ export default {
|
||||
searchparam: '',
|
||||
allCourses: [],
|
||||
sortBy: null,
|
||||
multiWeekIds: new Set()
|
||||
multiWeekIds: new Set(),
|
||||
favorites: new Set()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -50,7 +51,7 @@ export default {
|
||||
{
|
||||
let dir = this.sortBy === 'lektor-asc' ? 1 : -1;
|
||||
|
||||
return result.sort((a, b) => {
|
||||
result = result.sort((a, b) => {
|
||||
let an = a.lektoren?.[0]?.kurzbz ?? '';
|
||||
let bn = b.lektoren?.[0]?.kurzbz ?? '';
|
||||
return an.localeCompare(bn) * dir;
|
||||
@@ -58,22 +59,26 @@ export default {
|
||||
}
|
||||
else if (this.sortBy === 'kw-asc')
|
||||
{
|
||||
return result.sort((a, b) => (a.start_kw ?? 0) - (b.start_kw ?? 0));
|
||||
result = result.sort((a, b) => (a.start_kw ?? 0) - (b.start_kw ?? 0));
|
||||
}
|
||||
else if (this.sortBy === 'kw-desc')
|
||||
{
|
||||
return result.sort((a, b) => (b.start_kw ?? 0) - (a.start_kw ?? 0));
|
||||
result = result.sort((a, b) => (b.start_kw ?? 0) - (a.start_kw ?? 0));
|
||||
}
|
||||
else if (this.sortBy === 'stunden-asc')
|
||||
{
|
||||
return result.sort((a, b) => (a.offenestunden ?? 0) - (b.offenestunden ?? 0));
|
||||
result = result.sort((a, b) => (a.offenestunden ?? 0) - (b.offenestunden ?? 0));
|
||||
}
|
||||
else if (this.sortBy === 'stunden-desc')
|
||||
{
|
||||
return result.sort((a, b) => (b.offenestunden ?? 0) - (a.offenestunden ?? 0));
|
||||
result = result.sort((a, b) => (b.offenestunden ?? 0) - (a.offenestunden ?? 0));
|
||||
}
|
||||
|
||||
return result;
|
||||
return [...result].sort((a, b) => {
|
||||
let ap = this.isPinned(a) ? 1 : 0;
|
||||
let bp = this.isPinned(b) ? 1 : 0;
|
||||
return bp - ap;
|
||||
});
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -124,7 +129,7 @@ export default {
|
||||
showname: `${e.lehrfach} ${e.lehrform}`,
|
||||
orig: {
|
||||
type: 'lehreinheit',
|
||||
lehreinheit_id: e.lehreinheit_id[0],
|
||||
lehreinheit_id: e.lehreinheit_id,
|
||||
blockung: e.stundenblockung,
|
||||
entry: e,
|
||||
}
|
||||
@@ -175,7 +180,7 @@ export default {
|
||||
},
|
||||
toggleMultiWeek(course)
|
||||
{
|
||||
let id = course.lehreinheit_id[0];
|
||||
let id = course.lehreinheit_id;
|
||||
let weekIds = new Set(this.multiWeekIds);
|
||||
if (weekIds.has(id))
|
||||
weekIds.delete(id);
|
||||
@@ -186,8 +191,27 @@ export default {
|
||||
},
|
||||
isMultiWeek(course)
|
||||
{
|
||||
return this.multiWeekIds.has(course.lehreinheit_id[0]);
|
||||
return this.multiWeekIds.has(course.lehreinheit_id);
|
||||
},
|
||||
togglePin(course)
|
||||
{
|
||||
let id = course.lehreinheit_id;
|
||||
let favs = new Set(this.favorites);
|
||||
if (favs.has(id))
|
||||
favs.delete(id);
|
||||
else
|
||||
favs.add(id);
|
||||
|
||||
this.favorites = favs;
|
||||
localStorage.setItem('tempus_coursepicker_favs', JSON.stringify([...favs]));
|
||||
},
|
||||
isPinned(course)
|
||||
{
|
||||
return this.favorites.has(course.lehreinheit_id);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.favorites = new Set(JSON.parse(localStorage.getItem('tempus_coursepicker_favs') || '[]'));
|
||||
},
|
||||
template: `
|
||||
<div class="course-picker d-flex flex-column h-100">
|
||||
@@ -229,8 +253,8 @@ export default {
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="studiengaenge.length <= 0" class="d-flex flex-column align-items-center justify-content-center text-center text-muted py-5 px-3 h-100">
|
||||
<span class="small fw-semibold mb-1">Keine Lehreinheiten</span>
|
||||
<span class="small">Wähle einen Studiengang, um Lehreinheiten anzuzeigen.</span>
|
||||
<span class="small fw-semibold mb-1">{{$p.t('lehre', 'cptitleempty')}}</span>
|
||||
<span class="small">{{$p.t('lehre', 'cpempty')}}</span>
|
||||
</div>
|
||||
<div v-else class="overflow-auto px-2 pb-2 flex-grow-1">
|
||||
<div
|
||||
@@ -238,13 +262,20 @@ export default {
|
||||
:key="course.lehreinheit_id"
|
||||
style="cursor:grab"
|
||||
:style="courseStyle(course)"
|
||||
class="course-picker-row"
|
||||
class="course-picker-row rounded-3 mb-2 p-2"
|
||||
:class="{ 'course-picker-row-pinned': isPinned(course) }"
|
||||
v-draggable:move.noimage="dragLehreinheitCollection(course)"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="d-flex gap-1">
|
||||
<div class="d-flex gap-1 align-items-start">
|
||||
<span class="fw-semibold small w-50" v-tooltip="course.lehrfach_bez">{{ course.lehrfach }} {{ course.lehrform }}</span>
|
||||
<span class="fw-semibold small w-50" v-tooltip="course.raumtypalternativ">{{ course.raumtyp }}</span>
|
||||
<i
|
||||
class="fa fa-thumbtack"
|
||||
:class="isPinned(course) ? 'text-primary' : 'text-muted'"
|
||||
style="cursor:pointer"
|
||||
@click.stop="togglePin(course)"
|
||||
></i>
|
||||
<i
|
||||
class="fa fa-calendar-week"
|
||||
:class="isMultiWeek(course) ? 'text-primary' : 'text-muted'"
|
||||
@@ -256,14 +287,15 @@ export default {
|
||||
|
||||
<!--TODO(david) entfernen, dient nur für das mappen mit der lvverwaltung-->
|
||||
<div class="d-flex gap-1">
|
||||
<span class="small w-50" v-tooltip="course.lehreinheit_id">{{ course.lehreinheit_id[0] }} </span>
|
||||
<span class="small w-50" v-tooltip="course.lehreinheit_id">{{ course.lehreinheit_id }} </span>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-1 text-muted">
|
||||
<div class="w-50 d-flex flex-column" v-tooltip="course.anmerkung">
|
||||
<div class="w-50 d-flex flex-column text-truncate" v-tooltip="course.anmerkung">
|
||||
<span
|
||||
v-for="verband in course.lehrverband"
|
||||
:key="verband">
|
||||
:key="verband"
|
||||
class="text-truncate">
|
||||
{{ verband }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -286,7 +318,7 @@ export default {
|
||||
{{ lektor.kurzbz }}
|
||||
</span>
|
||||
<span v-if="course.lektoren.length > 3" class="text-muted fst-italic">
|
||||
+{{ course.lektoren.length - 3 }} weitere...
|
||||
+{{ course.lektoren.length - 3 }} {{$p.t('lehre', 'cpmore')}}
|
||||
</span>
|
||||
</div>
|
||||
<span class="w-50 align-self-start">WR: {{ course.wochenrythmus }} Bl: {{ course.stundenblockung }}</span>
|
||||
|
||||
@@ -364,6 +364,16 @@ export default {
|
||||
if (newDate && luxon.DateTime.isDateTime(newDate) && newDate.isValid)
|
||||
this.calendarDate = newDate.toISODate();
|
||||
},
|
||||
updateCollision()
|
||||
{
|
||||
this.$api.call(ApiTempusConfig.updateCollision())
|
||||
.then(() => {
|
||||
this.$refs.config.reload();
|
||||
this.$fhcAlert.alertSuccess(this.$p.t('ui/settings_saved'));
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemErrors);
|
||||
|
||||
},
|
||||
toggleStatus(selected) {
|
||||
if (!selected || selected.length === 0) {
|
||||
this.visibleStatus = ['all'];
|
||||
|
||||
@@ -6,6 +6,18 @@ export function getTempusShortcuts(self) {
|
||||
skipWhenTyping: false,
|
||||
handler: () => self.focusSearchbar()
|
||||
},
|
||||
{
|
||||
key: 'f',
|
||||
ctrl: true,
|
||||
skipWhenTyping: false,
|
||||
handler: () => self.focusSearchbar()
|
||||
},
|
||||
{
|
||||
key: 'F9',
|
||||
ctrl: false,
|
||||
skipWhenTyping: false,
|
||||
handler: () => self.updateCollision('month')
|
||||
},
|
||||
{
|
||||
key: '1',
|
||||
ctrl: true,
|
||||
|
||||
@@ -3743,6 +3743,66 @@ $phrases = array(
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'lehre',
|
||||
'phrase' => 'cpempty',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Wähle einen Studiengang aus, um den LV-Teil anzuzeigen.',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Select a degree program to display the teaching unit.',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'lehre',
|
||||
'phrase' => 'cptitleempty',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Kein LV-Teil',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'No teaching unit',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'lehre',
|
||||
'phrase' => 'cpmore',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'weitere...',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'more...',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'lehre',
|
||||
|
||||
Reference in New Issue
Block a user