diff --git a/application/controllers/api/frontend/v1/LvMenu.php b/application/controllers/api/frontend/v1/LvMenu.php index 45936d9f5..068eaf580 100644 --- a/application/controllers/api/frontend/v1/LvMenu.php +++ b/application/controllers/api/frontend/v1/LvMenu.php @@ -36,7 +36,8 @@ class LvMenu extends FHCAPI_Controller public function __construct() { parent::__construct([ - 'getLvMenu' => self::PERM_LOGGED + 'getLvMenu' => self::PERM_LOGGED, + 'getMultipleLvMenu' => self::PERM_LOGGED ]); $this->load->model("ressource/Mitarbeiter_model"); @@ -62,23 +63,18 @@ class LvMenu extends FHCAPI_Controller /** * alternative function to get multiple lvMenus with a single http request */ - public function getMultipleLvMenu($lvMenuOptionList){ + public function getMultipleLvMenu(){ + $lvMenuOptionList = $this->input->post('lvMenuOptionList', true); $result =[]; foreach($lvMenuOptionList as $lvMenuOptions){ $lvMenu = $this->getLvMenu($lvMenuOptions['lvid'],$lvMenuOptions['studiensemester_kurzbz']); - if(isError($lvMenu)){ - // TODO: some lvMenu threw an error, handle error here - } + $result[$lvMenuOptions['lvid']]=$lvMenu; } $this->terminateWithSuccess($result); } - - /** - * - */ - public function getLvMenu($lvid, $studiensemester_kurzbz) - { + + private function getLvMenuInternal($lvid, $studiensemester_kurzbz) { // return early if parameters are missing if(!isset($lvid) || !isset($studiensemester_kurzbz)) @@ -89,14 +85,14 @@ class LvMenu extends FHCAPI_Controller // get the user if (!$user=getAuthUID()) - $this->terminateWithError($this->p->t('global', 'nichtAngemeldet')); + $this->terminateWithError($this->p->t('global', 'nichtAngemeldet')); // check if is_lector $is_lector = false; $mares = $this->Mitarbeiter_model->isMitarbeiter($user); if(hasData($mares)) { - $is_lector = getData($mares); + $is_lector = getData($mares); } // definition of user_is_allowed_to_upload @@ -105,7 +101,7 @@ class LvMenu extends FHCAPI_Controller // load lehrveranstaltung $lvres = $this->Lehrveranstaltung_model->load($lvid); - if(!hasData($lvres)) + if(!hasData($lvres)) { $this->terminateWithError('LV ' . $lvid . ' not found.'); } @@ -124,7 +120,7 @@ class LvMenu extends FHCAPI_Controller $stgres = $this->Studiengang_model->load(strval($studiengang_kz)); if(!hasData($stgres)) { - $this->terminateWithError('Stg ' . $lv->studiengang_kz . ' not found.'); + $this->terminateWithError('Stg ' . $lv->studiengang_kz . ' not found.'); } $stg = (getData($stgres))[0]; $kurzbz = strtoupper($stg->typ . $stg->kurzbz); @@ -139,7 +135,7 @@ class LvMenu extends FHCAPI_Controller $angemeldet = false; $lesres = $this->Lehreinheit_model->getLehreinheitenForStudentAndStudienSemester( - $lvid, $user, $angezeigtes_stsem + $lvid, $user, $angezeigtes_stsem ); if(hasData($lesres) && count(getData($lesres)) > 0) @@ -148,7 +144,7 @@ class LvMenu extends FHCAPI_Controller // lehrfach $lehrfach_id=''; - + if(defined('CIS_LEHRVERANSTALTUNG_LEHRFACH_ANZEIGEN') && CIS_LEHRVERANSTALTUNG_LEHRFACH_ANZEIGEN) { // Wenn der eingeloggte User zu einer der Lehreinheiten zugeteilt ist @@ -211,8 +207,8 @@ class LvMenu extends FHCAPI_Controller foreach($fbs as $row) { $lehrfach_oe_kurzbz_arr[] = $row->oe_kurzbz; - if($this->PermissionLib->isBerechtigt('lehre', null, $row->oe_kurzbz) - || $this->PermissionLib->isBerechtigt('assistenz', null, $stg->oe_kurzbz)) + if($this->PermissionLib->isBerechtigt('lehre', null, $row->oe_kurzbz) + || $this->PermissionLib->isBerechtigt('assistenz', null, $stg->oe_kurzbz)) { $user_is_allowed_to_upload=true; } @@ -224,21 +220,21 @@ class LvMenu extends FHCAPI_Controller $menu = array(); $this->fhc_menu_lvinfo($menu, $lvid, $studiengang_kz, $lektor_der_lv, $is_lector, $lehrfach_oe_kurzbz_arr); - + $this->fhc_menu_feedback($menu, $angemeldet, $lvid); - + $this->fhc_menu_gesamtnote($menu, $angemeldet, $lvid, $lv, $is_lector, $angezeigtes_stsem); - + $this->fhc_menu_emailStudierende($menu, $user, $angemeldet, $lvid, $angezeigtes_stsem); - + $this->fhc_menu_abmeldung($menu, $user, $is_lector, $lvid, $angezeigtes_stsem); - + $this->fhc_menu_lehretools($menu, $lvid, $angezeigtes_stsem, $sprache); - + $this->fhc_menu_anrechnungStudent($menu, $lvid, $angezeigtes_stsem); - + $this->fhc_menu_anrechnungLector($menu, $angezeigtes_stsem); - + // Addons Menu Logic // ########################################################################################## @@ -272,18 +268,18 @@ class LvMenu extends FHCAPI_Controller 'permissionLib' => &$this->PermissionLib, 'phrasesLib' => &$this->PhrasesLib ]; - - Events::trigger('lvMenuBuild', - // passing $menu per reference - function & () use (&$menu) { - return $menu; - }, - $params + + Events::trigger('lvMenuBuild', + // passing $menu per reference + function & () use (&$menu) { + return $menu; + }, + $params ); // Menu sortieren // ########################################################################################## - + foreach ($menu as $key => $row){ // removes menu points that are not needed in the c4 lvUebersicht @@ -291,7 +287,7 @@ class LvMenu extends FHCAPI_Controller unset($menu[$key]); continue; } - + // fills pos array to sort the menu $pos[$key] = $row['position']; @@ -299,11 +295,18 @@ class LvMenu extends FHCAPI_Controller array_multisort($pos, SORT_ASC, SORT_NUMERIC, $menu); - // HTTP response - // ########################################################################################## + + return $menu; + } + + /** + * + */ + public function getLvMenu($lvid, $studiensemester_kurzbz) + { + $menu = $this->getLvMenuInternal($lvid, $studiensemester_kurzbz); $this->terminateWithSuccess($menu); - } private function fhc_menu_lvinfo(&$menu, $lvid, $studiengang_kz, $lektor_der_lv, $is_lector, $lehrfach_oe_kurzbz_arr){ diff --git a/application/models/education/Lehrveranstaltung_model.php b/application/models/education/Lehrveranstaltung_model.php index 5306ae50a..1c32096a9 100644 --- a/application/models/education/Lehrveranstaltung_model.php +++ b/application/models/education/Lehrveranstaltung_model.php @@ -1346,32 +1346,33 @@ class Lehrveranstaltung_model extends DB_Model // used for cis4 mylv mitarbeiter public function getLvsByMitarbeiterInSemester($mitarbeiter_uid, $sem_kurzbz) { - $qry = "SELECT - public.tbl_studiengang.studiengang_kz, - lehre.tbl_lehrveranstaltung.semester, - public.tbl_studiengang.bezeichnung as sg_bezeichnung, - public.tbl_studiengang.english as sg_bezeichnung_eng, - UPPER(tbl_studiengang.typ::varchar(1) || tbl_studiengang.kurzbz) as studiengang_kuerzel, - lehre.tbl_lehrveranstaltung.lehrveranstaltung_id, - lehre.tbl_lehrveranstaltung.bezeichnung, - lehre.tbl_lehrveranstaltung.bezeichnung_english as bezeichnung_eng, - lehre.tbl_lehreinheitmitarbeiter.semesterstunden as semesterstunden, - lehre.tbl_lehrveranstaltung.farbe, - lehre.tbl_lehrveranstaltung.lvinfo, - lehre.tbl_lehrveranstaltung.benotung, - lehre.tbl_lehrveranstaltung.orgform_kurzbz, - lehre.tbl_lehrveranstaltung.sprache, - lehre.tbl_lehrveranstaltung.ects, - lehre.tbl_lehrveranstaltung.incoming - FROM - lehre.tbl_lehreinheit JOIN lehre.tbl_lehreinheitmitarbeiter USING(lehreinheit_id) - JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id) - JOIN public.tbl_studiengang USING(studiengang_kz) - JOIN lehre.tbl_lehrveranstaltung as lehrfach ON(tbl_lehreinheit.lehrfach_id=lehrfach.lehrveranstaltung_id) - WHERE - tbl_lehreinheit.studiensemester_kurzbz = ? - AND mitarbeiter_uid = ? - ORDER BY studiengang_kuerzel, lehre.tbl_lehrveranstaltung.semester, lehre.tbl_lehrveranstaltung.bezeichnung"; + $qry = "SELECT * FROM ( + SELECT DISTINCT ON (lehre.tbl_lehrveranstaltung.lehrveranstaltung_id) + public.tbl_studiengang.studiengang_kz, + lehre.tbl_lehrveranstaltung.semester, + public.tbl_studiengang.bezeichnung as sg_bezeichnung, + public.tbl_studiengang.english as sg_bezeichnung_eng, + UPPER(tbl_studiengang.typ::varchar(1) || tbl_studiengang.kurzbz) as studiengang_kuerzel, + lehre.tbl_lehrveranstaltung.lehrveranstaltung_id, + lehre.tbl_lehrveranstaltung.bezeichnung, + lehre.tbl_lehrveranstaltung.bezeichnung_english as bezeichnung_eng, + TRUNC(lehre.tbl_lehreinheitmitarbeiter.semesterstunden) as semesterstunden, + lehre.tbl_lehrveranstaltung.farbe, + lehre.tbl_lehrveranstaltung.lvinfo, + lehre.tbl_lehrveranstaltung.benotung, + lehre.tbl_lehrveranstaltung.orgform_kurzbz, + lehre.tbl_lehrveranstaltung.sprache, + lehre.tbl_lehrveranstaltung.ects, + lehre.tbl_lehrveranstaltung.incoming + FROM + lehre.tbl_lehreinheit JOIN lehre.tbl_lehreinheitmitarbeiter USING(lehreinheit_id) + JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id) + JOIN public.tbl_studiengang USING(studiengang_kz) + JOIN lehre.tbl_lehrveranstaltung as lehrfach ON(tbl_lehreinheit.lehrfach_id=lehrfach.lehrveranstaltung_id) + WHERE + tbl_lehreinheit.studiensemester_kurzbz = ? + AND mitarbeiter_uid = ?) as distincted_by_lva_id + ORDER BY studiengang_kuerzel, semester, bezeichnung"; return $this->execReadOnlyQuery($qry, [$sem_kurzbz, $mitarbeiter_uid]); } diff --git a/public/js/api/factory/addons.js b/public/js/api/factory/addons.js index 23fd19e39..90030d21f 100644 --- a/public/js/api/factory/addons.js +++ b/public/js/api/factory/addons.js @@ -21,5 +21,20 @@ export default { method: 'get', url: `/api/frontend/v1/LvMenu/getLvMenu/${lvid}/${studiensemester_kurzbz}` }; + }, + getMultipleLvMenu(lvas, studiensemester_kurzbz) { + // format params for backend bulk function + const lvMenuOptionList = lvas.map(lva => { + return { + lvid: lva.lehrveranstaltung_id, + studiensemester_kurzbz + } + }) + + return { + method: 'post', + url: `/api/frontend/v1/LvMenu/getMultipleLvMenu`, + params: { lvMenuOptionList } + }; } }; \ No newline at end of file diff --git a/public/js/components/Cis/Mylv/MyLv.js b/public/js/components/Cis/Mylv/MyLv.js index 4bbc161bd..b4b5f1a6b 100644 --- a/public/js/components/Cis/Mylv/MyLv.js +++ b/public/js/components/Cis/Mylv/MyLv.js @@ -1,5 +1,6 @@ -import MylvSemester from "./Semester.js"; -import Phrasen from "../../../mixins/Phrasen.js"; +import MylvSemesterCards from "./Semester.js"; +import MylvTable from "./Table.js"; +import ApiAddons from "../../../api/factory/addons.js" // TODO(chris): phrase: global/studiensemester_auswaehlen // TODO(chris): phrase: next & prev +aria-label @@ -7,22 +8,23 @@ import Phrasen from "../../../mixins/Phrasen.js"; export default { name: 'MyLv', components: { - MylvSemester + MylvSemesterCards, + MylvTable }, - mixins: [ - Phrasen - ], data: () => { return { firstLoad: true, studiensemester: null, lvs: {}, - currentSemester: null + currentSemester: null, + lvMenues: null, + mode: 'table' // TODO: load from local storage }; }, provide() { return { - type: Vue.computed(() => this.type) + type: Vue.computed(() => this.type), + lvMenues: Vue.computed(() => this.lvMenues) } }, inject: ['isStudent', 'isMitarbeiter'], @@ -46,7 +48,12 @@ export default { axios.get(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/components/Cis/Mylv/Lvs/' + this.currentSemester).then(res => { this.lvs[this.currentSemester].lvs = res.data.retval || []; this.firstLoad = false; - }); + + this.$api.call(ApiAddons.getMultipleLvMenu(this.lvs[this.currentSemester].lvs, this.currentSemester)).then(res => { + this.lvMenues = res.data + }) + + }) } return this.lvs[this.currentSemester]; }, @@ -79,6 +86,9 @@ export default { } }, methods: { + clickMode(evt, mode) { + this.mode = mode + }, prevSem() { this.$refs.studiensemester.selectedIndex--; this.$refs.studiensemester.dispatchEvent(new Event('change', { bubbles: true })); @@ -129,11 +139,32 @@ export default { +
+
+ + +
+
- + +
diff --git a/public/js/components/Cis/Mylv/Semester.js b/public/js/components/Cis/Mylv/Semester.js index dbfddb987..e8f263192 100644 --- a/public/js/components/Cis/Mylv/Semester.js +++ b/public/js/components/Cis/Mylv/Semester.js @@ -12,11 +12,7 @@ export default { }, props: { semester: [String, Number], - lvs: Array, - mode: { - type: String, - default: 'Cards' - } + lvs: Array }, computed: { ready() { return this.lvs !== null; }, @@ -41,7 +37,8 @@ export default { return this.lvs.filter(lv => lv.studiengang_kz == studiengang.studiengang_kz && lv.semester == studiengang.semester); } }, - template: `
+ template: ` +
diff --git a/public/js/components/Cis/Mylv/Semester/Studiengang.js b/public/js/components/Cis/Mylv/Semester/Studiengang.js index ba6b4f0ca..1b0df068d 100644 --- a/public/js/components/Cis/Mylv/Semester/Studiengang.js +++ b/public/js/components/Cis/Mylv/Semester/Studiengang.js @@ -32,7 +32,8 @@ export default { return lv.benotung ? lv.znote || lv.lvnote || null : null; } }, - template: `
+ template: ` +

{{$p.user_language.value === 'English' ? sg_bezeichnung_eng : bezeichnung}} - {{kuerzel}} {{semester}}.{{$p.t('lehre/semester')}} diff --git a/public/js/components/Cis/Mylv/Semester/Studiengang/Lv.js b/public/js/components/Cis/Mylv/Semester/Studiengang/Lv.js index 81d5921c1..c1afd65d0 100644 --- a/public/js/components/Cis/Mylv/Semester/Studiengang/Lv.js +++ b/public/js/components/Cis/Mylv/Semester/Studiengang/Lv.js @@ -1,6 +1,4 @@ import LvPruefungen from "./Lv/Pruefungen.js"; -import LvInfo from "./Lv/Info.js"; -import Phrasen from "../../../../../mixins/Phrasen.js"; import ApiLehre from '../../../../../api/factory/lehre.js'; import ApiAddons from '../../../../../api/factory/addons.js'; @@ -9,9 +7,6 @@ import ApiAddons from '../../../../../api/factory/addons.js'; export default { name: 'Lv', - mixins: [ - Phrasen - ], inject: ['studien_semester', 'type'], props: { lehrveranstaltung_id: [Number, String], @@ -115,7 +110,6 @@ export default { } }, created() { - // TODO: check if this isnt a race condition in disguise if(this.type == 'student') { this.$api .call(ApiLehre.getStudentPruefungen(this.lehrveranstaltung_id)) diff --git a/public/js/components/Cis/Mylv/Table.js b/public/js/components/Cis/Mylv/Table.js new file mode 100644 index 000000000..f1b624b01 --- /dev/null +++ b/public/js/components/Cis/Mylv/Table.js @@ -0,0 +1,101 @@ +import {CoreFilterCmpt} from "../../../components/filter/Filter.js"; + +export default { + name: 'MylvTable', + components: { + CoreFilterCmpt + }, + props: { + semester: [String], + lvs: Array, + }, + data() { + return { + phrasenPromise: null, + phrasenResolved: false, + tabulatorUuid: Vue.ref(0), + tableBuiltResolve: null, + tableBuiltPromise: null, + mylvTableOptions: { + height: Vue.ref(400), + index: 'lehrveranstaltung_id', + layout: 'fitDataStretch', + placeholder: this.$p.t('global/noDataAvailable'), + columns: [ + {title: Vue.computed(() => this.$p.t('lehre/studiengang')), field: 'sg_bezeichnung', widthGrow: 1}, + {title: Vue.computed(() => this.$p.t('global/bezeichnung')), field: 'bezeichnung', widthGrow: 2}, + {title: Vue.computed(() => this.$p.t('lehre/orgform')), field: 'orgform_kurzbz', widthGrow: 1}, + {title: Vue.computed(() => this.$p.t('admission/stg_kurz')), field: 'studiengang_kuerzel', widthGrow: 1}, + {title: Vue.computed(() => this.$p.t('global/actions')), + field: 'menu', formatter: this.actionFormatter, widthGrow: 1} + ], + persistence: false, + persistenceID: "mylv_2026_04_17" + }, + mylvTableEventHandlers: [ + { + event: "tableBuilt", + handler: async () => { + this.tableBuiltResolve() + } + } + ] + } + }, + computed: { + ready() { return this.lvs !== null; }, + + }, + methods: { + handleUuidDefined(uuid) { + this.tabulatorUuid = uuid + }, + tableResolve(resolve) { + this.tableBuiltResolve = resolve + }, + actionFormatter() { + return '' + }, + async setupData() { + this.$refs.mylvTable.tabulator.setData(this.lvs); + }, + async setupMounted() { + + this.tableBuiltPromise = new Promise(this.tableResolve) + await this.tableBuiltPromise + + this.setupData() + + const tableID = this.tabulatorUuid ? ('-' + this.tabulatorUuid) : '' + const tableDataSet = document.getElementById('filterTableDataset' + tableID); + if(!tableDataSet) return + const rect = tableDataSet.getBoundingClientRect(); + + const h = window.visualViewport.height - rect.top - 100 + if(this.$refs.mylvTable) { + this.$refs.mylvTable.$refs.table.style.setProperty('height', h+'px') + } + + } + }, + created() { + this.phrasenPromise = this.$p.loadCategory(['global']) + this.phrasenPromise.then(()=> {this.phrasenResolved = true}) + }, + mounted() { + this.setupMounted() + }, + template: ` +
+ +
` +}; \ No newline at end of file diff --git a/public/js/components/Cis/Raumsuche/Raumsuche.js b/public/js/components/Cis/Raumsuche/Raumsuche.js index 365da4911..58c3bbeb6 100644 --- a/public/js/components/Cis/Raumsuche/Raumsuche.js +++ b/public/js/components/Cis/Raumsuche/Raumsuche.js @@ -70,8 +70,8 @@ export const Raumsuche = { handler: async () => { this.tableBuiltResolve() } - } - ]}; + }] + }; }, methods: { tableResolve(resolve) {