mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-06-24 23:49:28 +00:00
Tabs Component
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
use CI3_Events as Events;
|
||||
|
||||
/**
|
||||
* NOTE(chris): example:
|
||||
Events::on('stv_conf_student', function (&$res) {
|
||||
$res['test'] = [
|
||||
'title' => 'TEST',
|
||||
'component' => './Stv/Studentenverwaltung/Details/Notizen.js'
|
||||
];
|
||||
});
|
||||
*/
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
use CI3_Events as Events;
|
||||
|
||||
class Config extends FHC_Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
// TODO(chris): access!
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function student()
|
||||
{
|
||||
$result = [];
|
||||
$result['details'] = [
|
||||
'title' => 'Details',
|
||||
'component' => './Stv/Studentenverwaltung/Details/Details.js'
|
||||
];
|
||||
$result['kontakt'] = [
|
||||
'title' => 'Kontakt',
|
||||
'component' => './Stv/Studentenverwaltung/Details/Kontakt.js'
|
||||
];
|
||||
$result['notizen'] = [
|
||||
'title' => 'Notizen',
|
||||
'component' => './Stv/Studentenverwaltung/Details/Notizen.js'
|
||||
];
|
||||
|
||||
Events::trigger('stv_conf_student', $result);
|
||||
|
||||
$this->outputJsonSuccess($result);
|
||||
}
|
||||
|
||||
public function students()
|
||||
{
|
||||
$this->outputJsonSuccess([]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class CI3_Events
|
||||
{
|
||||
const PRIORITY_LOW = 200;
|
||||
const PRIORITY_NORMAL = 100;
|
||||
const PRIORITY_HIGH = 10;
|
||||
|
||||
private static $events = [];
|
||||
private static $eventsSorted = [];
|
||||
|
||||
public static function on($event, $function, $priority = self::PRIORITY_NORMAL)
|
||||
{
|
||||
if (!isset(self::$events[$event]))
|
||||
self::$events[$event] = [];
|
||||
|
||||
self::$events[$event][] = [$priority, $function];
|
||||
|
||||
if (!isset(self::$eventsSorted[$event]))
|
||||
self::$eventsSorted[$event] = true;
|
||||
else
|
||||
self::$eventsSorted[$event] = false;
|
||||
}
|
||||
|
||||
public static function trigger($event, &...$args)
|
||||
{
|
||||
if (!isset(self::$events[$event]))
|
||||
return;
|
||||
|
||||
if (!self::$eventsSorted[$event]) {
|
||||
usort(self::$events[$event], function ($a, $b) {
|
||||
return $a[0] - $b[0];
|
||||
});
|
||||
self::$eventsSorted[$event] = true;
|
||||
}
|
||||
|
||||
foreach (self::$events[$event] as $conf) {
|
||||
call_user_func_array($conf[1], $args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE(chris): Autoload Events config
|
||||
*/
|
||||
require_once(APPPATH.'config/Events.php');
|
||||
foreach (scandir(APPPATH.'config/extensions') as $dir)
|
||||
if ($dir[0] != '.' && file_exists(APPPATH.'config/extensions/'.$dir.'/Events.php'))
|
||||
require_once APPPATH.'config/extensions/'.$dir.'/Events.php';
|
||||
@@ -91,11 +91,6 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
lastSelected() {
|
||||
return this.selected[this.selected.length - 1];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onSelectVerband({link, studiengang_kz}) {
|
||||
this.studiengangKz = studiengang_kz;
|
||||
@@ -182,7 +177,7 @@ export default {
|
||||
<stv-list ref="stvList" v-model:selected="selected" :studiengang-kz="studiengangKz" :studiensemester-kurzbz="studiensemesterKurzbz"></stv-list>
|
||||
</template>
|
||||
<template #bottom>
|
||||
<stv-details :student="lastSelected"></stv-details>
|
||||
<stv-details :students="selected"></stv-details>
|
||||
</template>
|
||||
</vertical-split>
|
||||
</main>
|
||||
|
||||
@@ -1,66 +1,20 @@
|
||||
import accessibility from "../../../directives/accessibility.js";
|
||||
import FhcTabs from "../../Tabs.js";
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
accessibility
|
||||
components: {
|
||||
FhcTabs
|
||||
},
|
||||
props: {
|
||||
student: Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
current: this.$route.params.tab || 'details',
|
||||
tabTemplates: {
|
||||
details: 'Details',
|
||||
notizen: 'Notizen',
|
||||
kontakt: 'Kontakt'
|
||||
},
|
||||
tabs: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasNoStudent() {
|
||||
return !this.student || (Object.keys(this.student).length === 0 && this.student.constructor === Object);
|
||||
},
|
||||
currentComponent() {
|
||||
return this.tabs[this.current].component;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.tabs = Object.fromEntries(Object.entries(this.tabTemplates).map(([key, title]) => {
|
||||
return [key, {
|
||||
title,
|
||||
component: Vue.defineAsyncComponent(() => import("./Details/" + key.charAt(0).toUpperCase() + key.slice(1) + '.js'))
|
||||
}];
|
||||
}));
|
||||
students: Array
|
||||
},
|
||||
template: `
|
||||
<div class="stv-details h-100 pb-3 d-flex flex-column">
|
||||
<div v-if="hasNoStudent" class="justify-content-center d-flex h-100 align-items-center">Bitte StudentIn auswählen!</div>
|
||||
<template v-else>
|
||||
<div class="nav nav-tabs">
|
||||
<div
|
||||
v-for="({title}, key) in tabs"
|
||||
:key="comp"
|
||||
class="nav-item nav-link"
|
||||
:class="{active: key == current}"
|
||||
@click="current=key"
|
||||
:aria-current="key == current ? 'page' : ''"
|
||||
v-accessibility:tab
|
||||
>
|
||||
{{title}}
|
||||
</div>
|
||||
</div>
|
||||
<div style="flex: 1 1 0%; height: 0%" class="border-bottom border-start border-end overflow-auto p-3">
|
||||
<keep-alive>
|
||||
<suspense>
|
||||
<component :is="currentComponent" :student="student"></component>
|
||||
<template #fallback>
|
||||
Loading...
|
||||
</template>
|
||||
</suspense>
|
||||
</keep-alive>
|
||||
</div>
|
||||
<div v-if="!students?.length" class="justify-content-center d-flex h-100 align-items-center">
|
||||
Bitte StudentIn auswählen!
|
||||
</div>
|
||||
<template v-else>
|
||||
<fhc-tabs v-if="students.length == 1" :modelValue="students[0]" config-url="/components/stv/config/student" :default="$route.params.tab"></fhc-tabs>
|
||||
<fhc-tabs v-else :modelValue="students" config-url="/components/stv/config/students" :default="$route.params.tab"></fhc-tabs>
|
||||
</template>
|
||||
</div>`
|
||||
};
|
||||
@@ -37,7 +37,7 @@ export default {
|
||||
}
|
||||
},
|
||||
props: {
|
||||
student: Object
|
||||
modelValue: Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -65,7 +65,7 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
student(n) {
|
||||
modelValue(n) {
|
||||
this.updateStudent(n);
|
||||
},
|
||||
data: {
|
||||
@@ -104,7 +104,7 @@ export default {
|
||||
},
|
||||
save() {
|
||||
CoreRESTClient
|
||||
.post('components/stv/Student/save/' + this.student.prestudent_id, this.changed)
|
||||
.post('components/stv/Student/save/' + this.modelValue.prestudent_id, this.changed)
|
||||
.then(result => result.data)
|
||||
.then(result => {
|
||||
this.resetErrors();
|
||||
@@ -169,7 +169,7 @@ export default {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.updateStudent(this.student);
|
||||
this.updateStudent(this.modelValue);
|
||||
},
|
||||
//TODO(chris): Geburtszeit? Anzahl der Kinder?
|
||||
template: `
|
||||
|
||||
@@ -14,7 +14,7 @@ export default {
|
||||
PvAutoComplete
|
||||
},
|
||||
props: {
|
||||
student: Object
|
||||
modelValue: Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -25,7 +25,7 @@ export default {
|
||||
},
|
||||
created(){
|
||||
CoreRESTClient
|
||||
.get('components/stv/Kontakt/getAdressen/' + this.student.person_id)
|
||||
.get('components/stv/Kontakt/getAdressen/' + this.modelValue.person_id)
|
||||
.then(result => {
|
||||
this.adressen = result.data;
|
||||
})
|
||||
@@ -33,7 +33,7 @@ export default {
|
||||
console.error(err.response.data || err.message);
|
||||
});
|
||||
/* CoreRESTClient
|
||||
.get('components/stv/Kontakt/getKontakte/' + this.student.person_id)
|
||||
.get('components/stv/Kontakt/getKontakte/' + this.modelValue.person_id)
|
||||
.then(result => {
|
||||
this.kontakte = result.data;
|
||||
})
|
||||
@@ -41,7 +41,7 @@ export default {
|
||||
console.error(err.response.data || err.message);
|
||||
});
|
||||
CoreRESTClient
|
||||
.get('components/stv/Kontakt/getBankverbindung/' + this.student.person_id)
|
||||
.get('components/stv/Kontakt/getBankverbindung/' + this.modelValue.person_id)
|
||||
.then(result => {
|
||||
this.bankverbindungen = result.data;
|
||||
})
|
||||
@@ -62,19 +62,19 @@ export default {
|
||||
<!-- <button type="button" class="btn btn btn-outline-warning" @click="actionNewAdress()">new Adress</button>
|
||||
<button type="button" class="btn btn btn-outline-warning" @click="actionEditAdress(111444)">edit 111444</button>-->
|
||||
|
||||
<address-list ref="adressList" :uid="student.person_id"></address-list>
|
||||
<address-list ref="adressList" :uid="modelValue.person_id"></address-list>
|
||||
</fieldset>
|
||||
<br>
|
||||
<fieldset class="overflow-hidden">
|
||||
<legend>Kontakt</legend>
|
||||
<!-- {{this.kontakte}}-->
|
||||
<contact-list ref="contactList" :uid="student.person_id"></contact-list>
|
||||
<contact-list ref="contactList" :uid="modelValue.person_id"></contact-list>
|
||||
</fieldset>
|
||||
<br>
|
||||
<fieldset class="overflow-hidden">
|
||||
<legend>Bankverbindungen</legend>
|
||||
<!-- {{this.bankverbindungen}}-->
|
||||
<bankaccount-list ref="bankaccountList" :uid="student.person_id"></bankaccount-list>
|
||||
<bankaccount-list ref="bankaccountList" :uid="modelValue.person_id"></bankaccount-list>
|
||||
</fieldset>
|
||||
</div>`
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export default {
|
||||
props: {
|
||||
student: Object
|
||||
modelValue: Object
|
||||
},
|
||||
template: `
|
||||
<div class="stv-details-details h-100 pb-3">
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import {CoreRESTClient} from '../RESTClient.js';
|
||||
import accessibility from "../directives/accessibility.js";
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
accessibility
|
||||
},
|
||||
emits: [
|
||||
'update:modelValue'
|
||||
],
|
||||
props: {
|
||||
configUrl: String,
|
||||
default: String,
|
||||
modelValue: [String, Number, Boolean, Array, Object, Date, Function, Symbol]
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
current: null,
|
||||
tabs: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentTab() {
|
||||
if (this.tabs[this.current])
|
||||
return this.tabs[this.current];
|
||||
|
||||
return { component: 'div' };
|
||||
},
|
||||
value: {
|
||||
get() {
|
||||
return this.modelValue;
|
||||
},
|
||||
set(v) {
|
||||
this.$emit('update:modelValue', v);
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
CoreRESTClient
|
||||
.get(this.configUrl)
|
||||
.then(result => CoreRESTClient.getData(result.data))
|
||||
.then(result => {
|
||||
const tabs = {};
|
||||
// TODO(chris): check if result is array
|
||||
Object.entries(result).forEach(([key, config]) => {
|
||||
if (!config.component)
|
||||
return console.error('Component missing for ' + key);
|
||||
|
||||
tabs[key] = {
|
||||
component: Vue.defineAsyncComponent(() => import(config.component)),
|
||||
title: config.title || key,
|
||||
config: config.config,
|
||||
key
|
||||
}
|
||||
});
|
||||
if (tabs[this.default])
|
||||
this.current = this.default;
|
||||
else
|
||||
this.current = Object.keys(tabs)[0];
|
||||
this.tabs = tabs;
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
template: `
|
||||
<div class="fhc-tabs d-flex flex-column">
|
||||
<div class="nav nav-tabs">
|
||||
<div
|
||||
v-for="tab in tabs"
|
||||
:key="tab.key"
|
||||
class="nav-item nav-link"
|
||||
:class="{active: tab.key == current}"
|
||||
@click="current=tab.key"
|
||||
:aria-current="tab.key == current ? 'page' : ''"
|
||||
v-accessibility:tab
|
||||
>
|
||||
{{tab.title}}
|
||||
</div>
|
||||
</div>
|
||||
<div style="flex: 1 1 0%; height: 0%" class="border-bottom border-start border-end overflow-auto p-3">
|
||||
<keep-alive>
|
||||
<component :is="currentTab.component" v-model="value" :config="currentTab.config"></component>
|
||||
</keep-alive>
|
||||
</div>
|
||||
</div>`
|
||||
};
|
||||
Reference in New Issue
Block a user