From d13e2360b6dad80da567348c1013353a2fc2297e Mon Sep 17 00:00:00 2001
From: alex <alex@alexloehr.net>
Date: Thu, 23 Oct 2025 14:28:10 +0000
Subject: [PATCH] GS-2375
---
app.js | 10 +
vue/src/pages/KursDetailLp.vue | 150 +++++++++++++++++++++
vue/src/router.js | 8 +
vue/src/pages/KursDetail.vue | 239 ++++++++++++++++++---------------
vue/src/lib/api.js | 5
5 files changed, 304 insertions(+), 108 deletions(-)
diff --git a/app.js b/app.js
index 5a2a88d..acfd58f 100644
--- a/app.js
+++ b/app.js
@@ -190,6 +190,16 @@
return res.code(404).send({status: "error", msg: "not found"})
}
})
+ .get("/api/kurs/:refId/lp", async function (req, res) {
+ const {refId} = req.params
+ const {obj_id: objId} = await db.getObjIdFromRefId(refId)
+ let data = await db.getKursLp(objId)
+ if (data) {
+ return res.send(data)
+ } else {
+ return res.code(404).send({status: "error", msg: "not found"})
+ }
+ })
.get("/api/kurs/:refId/teilnehmerByRole", async function (req, res) {
const {refId} = req.params
const {obj_id} = await db.getObjIdFromRefId(refId)
diff --git a/vue/src/lib/api.js b/vue/src/lib/api.js
index 35959cf..26ff72b 100644
--- a/vue/src/lib/api.js
+++ b/vue/src/lib/api.js
@@ -53,6 +53,11 @@
return await resKurs.json()
}
+export async function getKursLp (kursId) {
+ let resKursLp = await fetch(`${apiBase}/kurs/${kursId}/lp?token=${apiToken.value}`)
+ return await resKursLp.json()
+}
+
/////// USER ////////////////////////////////////////////////////////////////
export async function getUsers (offset, limit, search) {
diff --git a/vue/src/pages/KursDetail.vue b/vue/src/pages/KursDetail.vue
index 38b4841..e4ebbcf 100644
--- a/vue/src/pages/KursDetail.vue
+++ b/vue/src/pages/KursDetail.vue
@@ -3,13 +3,13 @@
import {useRoute} from 'vue-router'
import {onMounted, reactive, ref} from "vue"
import {
- getKurs,
- getKursItems,
- getKursRoles,
- getKursTn,
- getKursTnByRole,
- iliasBase,
- popcornBase,
+ getKurs,
+ getKursItems,
+ getKursRoles,
+ getKursTn,
+ getKursTnByRole,
+ iliasBase,
+ popcornBase, routerBase,
} from "../lib/api.js"
import LinkExtern from "../components/LinkExtern.vue"
import dayjs from "dayjs"
@@ -34,27 +34,27 @@
/////////////////////////////////////////////////////////////////////////
-async function init () {
+async function init() {
- const dataKurs = await getKurs(kursId)
- console.log(dataKurs)
- kurs.value = dataKurs
+ const dataKurs = await getKurs(kursId)
+ console.log(dataKurs)
+ kurs.value = dataKurs
- const dataKursItems = await getKursItems(kursId)
- console.log(dataKursItems)
- kursItems.value = dataKursItems
+ const dataKursItems = await getKursItems(kursId)
+ console.log(dataKursItems)
+ kursItems.value = dataKursItems
- const dataKursTn = await getKursTn(kursId)
- console.log(dataKursTn)
- kursTn.value = dataKursTn
+ const dataKursTn = await getKursTn(kursId)
+ console.log(dataKursTn)
+ kursTn.value = dataKursTn
- const dataKursTnByRolle = await getKursTnByRole(kursId)
- console.log(dataKursTnByRolle)
- kursTnByRolle.value = dataKursTnByRolle
+ const dataKursTnByRolle = await getKursTnByRole(kursId)
+ console.log(dataKursTnByRolle)
+ kursTnByRolle.value = dataKursTnByRolle
- const dataKursRoles = await getKursRoles(kursId)
- console.log(dataKursRoles)
- kursRoles.value = dataKursRoles
+ const dataKursRoles = await getKursRoles(kursId)
+ console.log(dataKursRoles)
+ kursRoles.value = dataKursRoles
}
@@ -64,108 +64,133 @@
<template>
- <div>
- <h1>
- Kurs
- <small>{{ kurs?.title }}</small>
- </h1>
- <p v-if="error">{{ error }}</p>
+ <div>
+<!-- <pre>{{ kurs }}</pre>-->
+ <h1>
+ Kurs
+ <small>{{ kurs?.title }}</small>
+ </h1>
+ <p v-if="error">{{ error }}</p>
- <div class="kurs" v-if="kurs">
-
- <div>
- <span>ref_id</span>
- <div>
- <a :href="`${iliasBase}/goto.php?target=${kurs.type}_${kurs.ref_id}`" target="_blank">
- {{ kurs.ref_id }}
- <LinkExtern />
- </a>
- </div>
- </div>
-
- <div>
- <span>obj_id</span>
- <div>{{ kurs.obj_id }}</div>
- </div>
-
- <div>
- <span>offline</span>
- <div :class="{red:kurs.offline===1,green:kurs.offline===0}">
- {{ kurs.offline }}
- </div>
- </div>
-
- <div class="text-right" style="grid-column: span 1; justify-content: flex-end">
- <a :href="`${popcornBase}/anmeldungen?query=iliasId:${kurs.ref_id}&terminFilter=alle`" target="_blank">
- Search in 🍿
- </a>
- </div>
+ <div class="kurs" v-if="kurs">
- <div style="grid-column: span 2">
- <span style="">title</span>
- <div style="">{{ kurs.title }}</div>
- </div>
-
- <div style="grid-column: span 2;">
- <span>description</span>
- <div style="grid-column: span 3">{{ kurs.description }}</div>
- </div>
-
+ <div>
+ <span>ref_id</span>
+ <div>
+ <a :href="`${iliasBase}/goto.php?target=${kurs.type}_${kurs.ref_id}`" target="_blank">
+ {{ kurs.ref_id }}
+ <LinkExtern/>
+ </a>
+ </div>
</div>
- <div class="cols">
-
- <div>
- <h2>KursItems <small>({{ kursItems?.length }})</small></h2>
- <KursItems :kursItems="kursItems" />
- </div>
-
- <div>
- <h2>KursRoles <small>({{ kursRoles?.length }})</small></h2>
- <KursRoles :kursRoles="kursRoles" />
- </div>
-
+ <div>
+ <span>obj_id</span>
+ <div>{{ kurs.obj_id }}</div>
</div>
- <div class="cols">
- <div>
- <h2>KursTn by Members <small>({{ kursTn?.length }})</small></h2>
- <KursMembers :kursTn="kursTn" />
- </div>
-
- <div>
- <h2>KursTnByRole <small>({{ kursTnByRolle?.length }})</small></h2>
- <KursTnByRole :kursTnByRolle="kursTnByRolle" />
- </div>
-
+ <div>
+ <span>offline</span>
+ <div :class="{red:kurs.offline===1,green:kurs.offline===0}">
+ {{ kurs.offline }}
+ </div>
</div>
- </div>
+ <div class="text-right">
+ <div style="display:block; text-align:right;">
+ <a :href="`${popcornBase}/anmeldungen?query=iliasId:${kurs.ref_id}&terminFilter=alle`" target="_blank">
+ Search in 🍿
+ </a>
+ </div>
+ </div>
+
+ <div style="grid-column: span 3">
+ <span style="">title</span>
+ <div style="">{{ kurs.title }}</div>
+ </div>
+
+<!-- <div>-->
+<!-- <span>description</span>-->
+<!-- <div style="grid-column: span 3">{{ kurs.description }}</div>-->
+<!-- </div>-->
+
+ <div>
+ <span>Learning Progress</span>
+ <div>
+ <RouterLink :to="`${routerBase}/ui/kurs/${kurs?.ref_id}/lp`">
+ LP {{ kurs?.ref_id }}
+ </RouterLink>
+ </div>
+ </div>
+
+ </div>
+
+ <div class="cols">
+
+ <div>
+ <h2>KursItems <small>({{ kursItems?.length }})</small></h2>
+ <KursItems :kursItems="kursItems"/>
+ </div>
+
+ <div>
+ <h2>KursRoles <small>({{ kursRoles?.length }})</small></h2>
+ <KursRoles :kursRoles="kursRoles"/>
+ </div>
+
+ </div>
+
+ <div class="cols">
+ <div>
+ <h2>KursTn by Members <small>({{ kursTn?.length }})</small></h2>
+ <KursMembers :kursTn="kursTn"/>
+ </div>
+
+ <div>
+ <h2>KursTnByRole <small>({{ kursTnByRolle?.length }})</small></h2>
+ <KursTnByRole :kursTnByRolle="kursTnByRolle"/>
+ </div>
+
+ </div>
+
+ </div>
</template>
<style scoped lang="stylus">
.cols
- display flex;
- gap 2em
+ display flex;
+ gap 2em
.kurs
- padding 1em
- border 1px solid #aaa
- border-radius .33em
- box-shadow 1px 1px 3px #333 inset, 1px 1px 100px #ddd inset
- display grid;
- grid-template-columns 1fr 1fr 1fr 1fr
- gap 1em
- span
- font-variant small-caps
- color #555
- &>*
- display flex
- gap 1em
+ padding 1em
+ border 1px solid #aaa
+ border-radius .33em
+ box-shadow 1px 1px 3px #333 inset, 1px 1px 100px #ddd inset
+ display flex
+ flex-direction column
+ display grid;
+ grid-template-columns 1fr 1fr 1fr 1fr
+ gap 1em
+ span
+ font-variant small-caps
+ font-size 85%
+ color #555
+
+ & > *
+ display flex
+ flex 1 0 auto
+ justify-content start
+ //border 4px solid orange
+ align-items baseline
+ gap .66em
+
+ & > *
+ display flex
+ flex-direction row
+ gap .33em
</style>
diff --git a/vue/src/pages/KursDetailLp.vue b/vue/src/pages/KursDetailLp.vue
new file mode 100644
index 0000000..f903327
--- /dev/null
+++ b/vue/src/pages/KursDetailLp.vue
@@ -0,0 +1,150 @@
+<script setup>
+
+import {useRoute} from 'vue-router'
+import {onMounted, reactive, ref} from "vue"
+import {
+ getKurs,
+ getKursItems, getKursLp,
+ getKursRoles,
+ getKursTn,
+ getKursTnByRole,
+ iliasBase,
+ popcornBase, routerBase,
+} from "../lib/api.js"
+import LinkExtern from "../components/LinkExtern.vue"
+import dayjs from "dayjs"
+import KursItems from '../components/KursItems.vue'
+import KursRoles from '../components/KursRoles.vue'
+import KursMembers from '../components/KursMembers.vue'
+import KursTnByRole from '../components/KursTnByRole.vue'
+
+const route = useRoute()
+const kursId = route.params.kursId
+document.title = `Kurs LP ${kursId} | globus-ilias-rest`
+
+const kurs = ref(null)
+const kursLp = ref(null)
+const error = ref(null)
+
+onMounted(init)
+
+/////////////////////////////////////////////////////////////////////////
+
+
+async function init() {
+
+ const dataKurs = await getKurs(kursId)
+ console.log(dataKurs)
+ kurs.value = dataKurs
+
+ const dataKursLp = await getKursLp(kursId)
+ console.log({dataKursLp})
+ kursLp.value = dataKursLp
+ // kursLp.value = [...dataKursLp,...dataKursLp,...dataKursLp]
+}
+
+</script>
+
+<template>
+
+ <div>
+ <h1>
+ Kurs LP
+ <small>
+ <RouterLink :to="`${routerBase}/ui/kurs/${kurs?.ref_id}`">
+ {{ kurs?.title }}
+ </RouterLink>
+ </small>
+ </h1>
+
+ <p>Der Kurs Lernfortschritt (LP) wird u.a. aus der Tabelle <code>ut_lp_marks</code> gelesen.</p>
+
+ <p v-if="error">{{ error }}</p>
+
+ <br>
+
+ <div class="kurs-lp" v-if="kursLp">
+
+ <!-- <pre>{{ kursLp }}</pre>-->
+
+ <table class="w100p">
+ <thead>
+ <tr>
+<!-- <th>ref_id</th>-->
+<!-- <th>obj_id</th>-->
+ <!-- <th>title</th>-->
+ <th>usr_id</th>
+ <th>login</th>
+ <th>firstname</th>
+ <th>lastname</th>
+ <th>passed</th>
+ <th>status</th>
+ <th>status_changed</th>
+ <th>status_overwrite</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr v-for="item in kursLp">
+<!-- <td>{{ item.ref_id }}</td>-->
+<!-- <td>{{ item.obj_id }}</td>-->
+ <!-- <td>{{item.title}}</td>-->
+ <td>
+ <RouterLink :to="`${routerBase}/ui/user/${item.usr_id}`">
+ {{ item.usr_id }}
+ </RouterLink>
+ </td>
+ <td>{{ item.login }}</td>
+ <td>{{ item.firstname }}</td>
+ <td>{{ item.lastname }}</td>
+ <td>{{ item.passed }}</td>
+ <td>{{ item.status }}</td>
+ <td>{{ dayjs(item.status_changed).format("DD.MM.YYYY HH:mm:ss") }}</td>
+ <td>{{ item.status_overwrite }}</td>
+ </tr>
+ </tbody>
+ </table>
+
+
+ </div>
+
+
+ </div>
+
+</template>
+
+<style scoped lang="stylus">
+
+.cols
+ display flex;
+ gap 2em
+
+.kurs
+ padding 1em
+ border 1px solid #aaa
+ border-radius .33em
+ box-shadow 1px 1px 3px #333 inset, 1px 1px 100px #ddd inset
+ display flex
+ flex-direction column
+ display grid;
+ grid-template-columns 1fr 1fr 1fr 1fr
+ gap 1em
+
+ span
+ font-variant small-caps
+ font-size 85%
+ color #555
+
+ & > *
+ display flex
+ flex 1 0 auto
+ justify-content start
+ //border 4px solid orange
+ align-items baseline
+ gap .66em
+
+ & > *
+ display flex
+ flex-direction row
+ gap .33em
+
+</style>
diff --git a/vue/src/router.js b/vue/src/router.js
index 3fd319f..c19a76d 100644
--- a/vue/src/router.js
+++ b/vue/src/router.js
@@ -7,6 +7,7 @@
import UserDetail from './pages/UserDetail.vue'
import Kurse from './pages/Kurse.vue'
import KursDetail from './pages/KursDetail.vue'
+import KursDetailLp from "@/pages/KursDetailLp.vue";
import {routerBase} from "@/lib/api"
@@ -37,8 +38,13 @@
component: KursDetail,
meta: { title: 'KursDetail | globus-ilias-rest' }
},
+ {
+ path: `${routerBase}/ui/kurs/:kursId/lp`,
+ component: KursDetailLp,
+ meta: { title: 'KursDetail LP | globus-ilias-rest' }
+ },
]
-console.log(routes)
+// console.log(routes)
const router = createRouter({
history: createWebHistory(),
--
Gitblit v1.8.0