NotenTab: Document download/archive

This commit is contained in:
cgfhtw
2024-12-19 16:20:14 +01:00
parent 14eb27ae24
commit d899bf3393
4 changed files with 307 additions and 10 deletions
@@ -99,6 +99,8 @@ class Config extends FHCAPI_Controller
'usePoints' => defined('CIS_GESAMTNOTE_PUNKTE') && CIS_GESAMTNOTE_PUNKTE,
'edit' => 'both', // Possible values: both|header|inline
'delete' => 'both', // Possible values: both|header|inline
'documents' => 'both', // Possible values: both|header|inline
'documentslist' => $this->gradesDocumentsList()
]
];
@@ -235,4 +237,157 @@ class Config extends FHCAPI_Controller
]
] + $this->kontoColumns();
}
protected function gradesDocumentsList()
{
$permissioncheck = site_url("api/frontend/v1/documents/permissionAlternativeFormat/{studiengang_kz}");
$title_ger = $this->p->t("global", "deutsch");
$title_eng = $this->p->t("global", "englisch");
$title_ff = 'Zertifikat'; // TODO(chris): phrase
$title_lv = 'LV Zeugnis'; // TODO(chris): phrase
$link_ff = "documents/export/" .
"zertifikat.rdf.php/" .
"Zertifikat" .
"?stg_kz={studiengang_kz_lv}" .
"&uid={uid}" .
"&ss={studiensemester_kurzbz}" .
"&lvid={lehrveranstaltung_id}";
$link_lv_ger = "documents/export/" .
"lehrveranstaltungszeugnis.rdf.php/" .
"LVZeugnis" .
"?stg_kz={studiengang_kz}" .
"&uid={uid}" .
"&ss={studiensemester_kurzbz}" .
"&lvid={lehrveranstaltung_id}";
$link_lv_eng = "documents/export/" .
"lehrveranstaltungszeugnis.rdf.php/" .
"LVZeugnisEng" .
"?stg_kz={studiengang_kz}" .
"&uid={uid}" .
"&ss={studiensemester_kurzbz}" .
"&lvid={lehrveranstaltung_id}";
$archive_url = "api/frontend/v1/documents/archiveSigned";
$archive_response = $this->p->t("stv", "document_signed_and_archived");
$archive_post_ff = [
"xml" => "zertifikat.rdf.php",
"xsl" => "Zertifikat",
"stg_kz" => "{studiengang_kz_lv}",
"uid" => "{uid}",
"ss" => "{studiensemester_kurzbz}",
"lvid" => "{lehrveranstaltung_id}"
];
$archive_post_lv_ger = [
"xml" => "lehrveranstaltungszeugnis.rdf.php",
"xsl" => "LVZeugnis",
"stg_kz" => "{studiengang_kz}",
"uid" => "{uid}",
"ss" => "{studiensemester_kurzbz}",
"lvid" => "{lehrveranstaltung_id}"
];
$archive_post_lv_eng = [
"xml" => "lehrveranstaltungszeugnis.rdf.php",
"xsl" => "LVZeugnisEng",
"stg_kz" => "{studiengang_kz}",
"uid" => "{uid}",
"ss" => "{studiensemester_kurzbz}",
"lvid" => "{lehrveranstaltung_id}"
];
$list = [
[
'title' => '<i class="fa fa-download" title="Download"></i>', // TODO(chris): phrase
'children' => [
[
'title' => $title_ff,
'link' => site_url($link_ff)
],
[
'title' => $title_lv,
'children' => [
[
'title' => $title_ger,
'link' => site_url($link_lv_ger),
'children' => [
[
'title' => 'PDF',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_ger)
],
[
'title' => 'DOC',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_ger . "&output=doc")
],
[
'title' => 'ODT',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_ger . "&output=odt")
]
]
],
[
'title' => $title_eng,
'link' => site_url($link_lv_eng),
'children' => [
[
'title' => 'PDF',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_eng)
],
[
'title' => 'DOC',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_eng . "&output=doc")
],
[
'title' => 'ODT',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_eng . "&output=odt")
]
]
]
]
]
]
],
[
'title' => '<i class="fas fa-archive" title="Archivieren"></i>', // TODO(chris): phrase
'children' => [
[
'title' => $title_ff,
'action' => [
'url' => site_url($archive_url),
'post' => $archive_post_ff,
'response' => $archive_response
]
],
[
'title' => $title_lv,
'children' => [
[
'title' => $title_ger,
'action' => [
'url' => site_url($archive_url),
'post' => $archive_post_lv_ger,
'response' => $archive_response
]
],
[
'title' => $title_eng,
'action' => [
'url' => site_url($archive_url),
'post' => $archive_post_lv_eng,
'response' => $archive_response
]
]
]
]
]
]
];
return $list;
}
}
@@ -1,10 +1,12 @@
import {CoreFilterCmpt} from "../../../../filter/Filter.js";
import ZeugnisActions from './Zeugnis/Actions.js';
import ZeugnisDocuments from './Zeugnis/Documents.js';
export default {
components: {
CoreFilterCmpt,
ZeugnisActions
ZeugnisActions,
ZeugnisDocuments
},
inject: [
'config'
@@ -15,9 +17,27 @@ export default {
},
data() {
return {
tabulatorEvents: [],
tabulatorEvents: [
{
event: "dataLoaded",
handler: data => this.data = data.map(item => {
item.documentslist = document.createElement("div");
return item;
})
},
{
event: "rowSelected",
handler: row => row.getElement().style.zIndex = 12
},
{
event: "rowDeselected",
handler: row => row.getElement().style.zIndex = ''
}
],
stdsem: '',
lastGradeList: []
lastGradeList: [],
lastClickedRow: null,
data: []
};
},
computed: {
@@ -125,13 +145,14 @@ export default {
{ field: 'lehrveranstaltung_bezeichnung_english', title: 'Englisch', visible: false }
];
const hasDownload = ['both', 'inline'].includes(this.config.download);
const hasDocuments = ['both', 'inline'].includes(this.config.documents);
const hasDelete = ['both', 'inline'].includes(this.config.delete);
if (hasDownload || hasDelete) {
if (hasDocuments || hasDelete) {
columns.push({
field: 'actions',
title: 'Actions',
cssClass: "overflow-visible",
headerSort: false,
formatter: cell => {
// get row data
@@ -141,13 +162,20 @@ export default {
let container = document.createElement('div');
container.className = "d-flex gap-2 justify-content-end";
if (hasDocuments) {
container.append(data.documentslist);
}
if (hasDelete) {
let deleteButton = document.createElement('button');
deleteButton.className = 'btn btn-outline-secondary';
deleteButton.innerHTML = '<i class="fa fa-trash"></i>';
const icon = document.createElement('i');
icon.className = 'fa fa-trash';
icon.title = this.$p.t('ui/loeschen');
deleteButton.append(icon);
deleteButton.addEventListener('click', evt => {
evt.stopPropagation();
this.deleteGrade(data);
this.deleteGrade(data);// TODO(chris): test with new data object
});
container.append(deleteButton);
}
@@ -202,7 +230,7 @@ export default {
.then(result => result ? data : Promise.reject({handled:true}))
.then(this.$fhcApi.factory.stv.grades.deleteCertificate)
.then(this.$refs.table.reloadTable)
.then(() => this.$fhcAlert.alertSuccess('deleted')) // TODO(chris): phrase
.then(() => this.$fhcAlert.alertSuccess(this.$p.t('ui/successDelete')))
.catch(this.$fhcAlert.handleSystemError);
}
},
@@ -223,5 +251,12 @@ export default {
<zeugnis-actions :selected="selected" @set-grade="setGrade" @delete-grade="deleteGrade"></zeugnis-actions>
</template>
</core-filter-cmpt>
<Teleport
v-for="grade in data"
:key="grade.uid + '_' + grade.studiensemester_kurzbz + '_' + grade.lehrveranstaltung_id"
:to="grade.documentslist"
>
<zeugnis-documents :data="grade" :list="config.documentslist"></zeugnis-documents>
</Teleport>
</div>`
};
@@ -1,11 +1,13 @@
import CoreForm from '../../../../../Form/Form.js';
import FormInput from '../../../../../Form/Input.js';
import ZeugnisDocuments from './Documents.js';
export default {
components: {
CoreForm,
FormInput
FormInput,
ZeugnisDocuments
},
emits: [
'setGrade',
@@ -117,13 +119,20 @@ export default {
<option v-for="grade in grades" :key="grade.note" :value="grade.note">{{ grade.bezeichnung }}</option>
</select>
</template>
<zeugnis-documents
v-if="['both', 'header'].includes(config.documents)"
:data="selected.find(Boolean)"
:list="config.documentslist"
:disabled="!selected.length"
>
</zeugnis-documents>
<button
v-if="['both', 'header'].includes(config.delete)"
class="btn btn-outline-secondary"
:disabled="!selected.length"
@click="deleteGrades"
>
<i class="fa fa-trash"></i>
<i class="fa fa-trash" :title="$p.t('ui/loeschen')"></i>
</button>
</div>`
};
@@ -0,0 +1,98 @@
// NOTE(chris): cache calls globally to prevent multiple calls on the same source
const calledPermissionUrls = {};
async function callPermissionUrl($fhcApi, url) {
if (!calledPermissionUrls[url]) {
calledPermissionUrls[url] = $fhcApi.get(url);
}
return (await calledPermissionUrls[url]).data;
}
export default {
components: {
PvTieredMenu: primevue.tieredmenu
},
props: {
list: Array,
data: Object
},
data() {
return {
filteredList: []
};
},
watch: {
async data() {
this.filteredList = await this.copyListPart(this.list);
}
},
methods: {
addParamsToString(link) {
for (var k in this.data)
link = link.replace("{" + k + "}", this.data[k]);
return link;
},
async copyListPart(list) {
let result = [], res;
for (const part of list) {
if (part.permissioncheck) {
if (!this.data)
continue;
let permissioncheckUrl = part.permissioncheck;
for (const k in this.data) {
permissioncheckUrl = permissioncheckUrl.replace("{" + k + "}", this.data[k]);
}
if (!await callPermissionUrl(this.$fhcApi, permissioncheckUrl))
continue;
}
const item = {label: part.title};
if (part.children)
item.items = await this.copyListPart(part.children);
if (!item.items || !item.items.length) {
if (part.action && part.action.url) {
item.command = () => {
const post = {};
if (part.action.post)
Object.entries(part.action.post)
.forEach(
([key, value]) =>
post[key] = value[0] == '{'
? this.data[value.slice(1,-1)]
: value
);
this.$fhcApi
.post(this.addParamsToString(part.action.url), post)
.then(() => part.action.response || 'TODO(chris): phrase default')
.then(this.$fhcAlert.alertSuccess)
.catch(this.$fhcAlert.handleSystemError);
};
} else if(part.link) {
item.url = this.addParamsToString(part.link);
item.target = '_blank';
}
}
result.push(item);
}
return result;
}
},
async created() {
this.filteredList = await this.copyListPart(this.list);
},
template: `
<div class="stv-details-noten-zeugnis-documents d-inline-flex gap-2">
<template v-for="(item, i) in filteredList" :key="i">
<button
type="button"
label="Toggle"
@click="evt => $refs.menu[i].toggle(evt)"
aria-haspopup="true"
class="btn btn-outline-secondary dropdown-toggle"
v-html="item.label"
v-bind="$attrs"
/>
<pv-tiered-menu ref="menu" :model="item.items" popup />
</template>
</div>`
};