Multistatus Adaptions Design

This commit is contained in:
ma0068
2024-04-29 10:51:02 +02:00
22 changed files with 1480 additions and 1405 deletions
@@ -0,0 +1,90 @@
<?php
/**
* Copyright (C) 2024 fhcomplete.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
* This controller operates between (interface) the JS (GUI) and the back-end
* Provides data to the ajax get calls about the Studiengang filter
* Listens to ajax post calls to change the Studiengang filter data
* This controller works with JSON calls on the HTTP GET or POST and the output is always JSON
*/
class Filter extends FHCAPI_Controller
{
/**
* Calls the parent's constructor and prepares libraries and phrases
*/
public function __construct()
{
// TODO(chris): permissions
parent::__construct([
'getStg' => 'student/stammdaten:r',#self::PERM_LOGGED,
'setStg' => 'student/stammdaten:r'#self::PERM_LOGGED
]);
// Load models
$this->load->model('system/Variable_model', 'VariableModel');
}
//------------------------------------------------------------------------------------------------------------------
// Public methods
/**
* Get current setting
*
* @return void
*/
public function getStg()
{
$result = $this->VariableModel->getVariables(getAuthUID(), ['kontofilterstg']);
#$data = $this->getDataOrTerminateWithError($result);
if (isError($result))
$this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL);
$data = $result->retval;
$this->terminateWithSuccess($data['kontofilterstg'] == 'true');
}
/**
* Set current setting
*
* @return void
*/
public function setStg()
{
$this->load->library('form_validation');
$studiengang_kz = $this->input->post('studiengang_kz');
if ($studiengang_kz === null) {
$this->form_validation->set_rules('studiengang_kz', 'Studiengang', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
}
$result = $this->VariableModel->setVariable(getAuthUID(), 'kontofilterstg', $studiengang_kz ? 'true' : 'false');
#$this->getDataOrTerminateWithError($result);
if (isError($result))
$this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL);
$this->terminateWithSuccess(true);
}
}
@@ -49,7 +49,7 @@ class Konto extends FHCAPI_Controller
// Load language phrases
$this->loadPhrases([
'ui'
'konto'
]);
}
@@ -175,22 +175,21 @@ class Konto extends FHCAPI_Controller
return $row->nachname . ' ' . $row->vorname;
}, $result);
// TODO(chris): Phrases
$result = $this->p->t('konto', 'buchung_vorhanden') . "\n";
$result = $this->p->t('konto', 'confirm_overwrite') . "\n";
if (count($persons) > 10) {
$result .= "-" . implode("\n-", array_slice($persons, 0, 10)) . "\n";
if (count($persons) == 11) {
$result .= "\n" . $this->p->t('konto', 'and_1_additional_person');
$result .= "\n" . $this->p->t('konto', 'confirm_overwrite_1_add_pers');
} else {
$result .= "\n" . $this->p->t('konto', 'and_x_additional_person', [
$result .= "\n" . $this->p->t('konto', 'confirm_overwrite_x_add_pers', [
'x' => count($persons) - 10
]);
}
} else {
$result .= "-" . implode("\n-", $persons) . "\n";
}
$result .= $this->p->t('konto', 'proceed');
$result .= $this->p->t('konto', 'confirm_overwrite_proceed');
$this->addError($result, 'confirm');
@@ -327,8 +326,8 @@ class Konto extends FHCAPI_Controller
'label' => 'Buchung # ' . $buchungsnr,
'rules' => 'regex_match[/^$/]',
'errors' => [
'regex_match' => 'Gegenbuchungen koennen nur auf die obersten Buchungen getaetigt werden'
] // TODO(chris): phrase
'regex_match' => $this->p->t('konto', 'error_counter_level')
]
];
}
}
@@ -355,9 +354,9 @@ class Konto extends FHCAPI_Controller
if ($betrag === null) {
$this->addError($this->p->t(
'konto',
'Buchung #{buchungsnr} does not exist',
'error_missing',
$buchung
), self::ERROR_TYPE_GENERAL); // TODO(chris): phrase
), self::ERROR_TYPE_GENERAL);
continue;
}
@@ -482,7 +481,9 @@ class Konto extends FHCAPI_Controller
$result = $result->retval;
if (!$result)
$this->terminateWithError('buchung not found', self::ERROR_TYPE_GENERAL); // TODO(chris): phrase
$this->terminateWithError($this->p->t('konto', 'error_missing', [
'buchungsnr' => $buchungsnr
]), self::ERROR_TYPE_GENERAL);
$_POST['studiengang_kz'] = current($result)->studiengang_kz;
@@ -500,7 +501,7 @@ class Konto extends FHCAPI_Controller
if (isError($result)) {
if (getCode($result) != 42)
$this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL);
$this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); // TODO(chris): phrase
$this->terminateWithError($this->p->t('konto', 'error_delete_level'), self::ERROR_TYPE_GENERAL);
}
$this->terminateWithSuccess();
+125 -30
View File
@@ -15,53 +15,61 @@ class Config extends FHC_Controller
$this->load->library('AuthLib');
$this->load->library('PermissionLib');
$this->loadPhrases([
'global',
'person',
'lehre',
'stv',
'konto'
]);
}
public function student()
{
// TODO(chris): phrases
$result = [];
$result['details'] = [
'title' => 'Details',
'title' => $this->p->t('stv', 'tab_details'),
'component' => './Stv/Studentenverwaltung/Details/Details.js'
];
$result['notizen'] = [
'title' => 'Notizen',
$result['notes'] = [
'title' => $this->p->t('stv', 'tab_notes'),
'component' => './Stv/Studentenverwaltung/Details/Notizen.js'
];
$result['kontakt'] = [
'title' => 'Kontakt',
$result['contact'] = [
'title' => $this->p->t('stv', 'tab_contact'),
'component' => './Stv/Studentenverwaltung/Details/Kontakt.js'
];
$result['prestudent'] = [
'title' => 'PreStudentIn',
'title' => $this->p->t('stv', 'tab_prestudent'),
'component' => './Stv/Studentenverwaltung/Details/Prestudent.js'
];
$result['status'] = [
'title' => 'Status',
'component' => './Stv/Studentenverwaltung/Details/Status.js'
];
$result['multistatus'] = [
'title' => 'MultiStatus',
'title' => 'Status',
'component' => './Stv/Studentenverwaltung/Details/MultiStatus.js'
];
$result['konto'] = [
'title' => 'Konto',
'component' => './Stv/Studentenverwaltung/Details/Konto.js'
];
$result['banking'] = [
'title' => $this->p->t('stv', 'tab_banking'),
'component' => './Stv/Studentenverwaltung/Details/Konto.js',
'config' => [
'showZahlungsbestaetigung' => (defined('ZAHLUNGSBESTAETIGUNG_ANZEIGEN') && ZAHLUNGSBESTAETIGUNG_ANZEIGEN),
'showBuchungsnr' => $this->permissionlib->isBerechtigt('admin'),
'showMahnspanne' => (!defined('FAS_KONTO_SHOW_MAHNSPANNE') || FAS_KONTO_SHOW_MAHNSPANNE===true),
'showCreditpoints' => (defined('FAS_KONTO_SHOW_CREDIT_POINTS') && FAS_KONTO_SHOW_CREDIT_POINTS == 'true'),
'columns' => $this->kontoColumns(),
'additionalCols' => []
]
];
$result['betriebsmittel'] = [
'title' => 'Betriebsmittel',
$result['resources'] = [
'title' => $this->p->t('stv', 'tab_resources'),
'component' => './Stv/Studentenverwaltung/Details/Betriebsmittel.js'
];
$result['noten'] = [
'title' => 'Noten',
$result['grades'] = [
'title' => $this->p->t('stv', 'tab_grades'),
'component' => './Stv/Studentenverwaltung/Details/Noten.js'
];
@@ -74,35 +82,30 @@ class Config extends FHC_Controller
public function students()
{
// TODO(chris): phrases
$result = [];
$result['konto'] = [
'title' => 'Konto',
$result['banking'] = [
'title' => $this->p->t('stv', 'tab_banking'),
'component' => './Stv/Studentenverwaltung/Details/Konto.js',
'config' => [
'showZahlungsbestaetigung' => (defined('ZAHLUNGSBESTAETIGUNG_ANZEIGEN') && ZAHLUNGSBESTAETIGUNG_ANZEIGEN),
'showBuchungsnr' => $this->permissionlib->isBerechtigt('admin'),
'showMahnspanne' => (!defined('FAS_KONTO_SHOW_MAHNSPANNE') || FAS_KONTO_SHOW_MAHNSPANNE===true),
'showCreditpoints' => (defined('FAS_KONTO_SHOW_CREDIT_POINTS') && FAS_KONTO_SHOW_CREDIT_POINTS == 'true'),
'columns' => $this->kontoColumnsMultiPerson(),
'additionalCols' => []
]
];
$result['multistatus'] = [
'title' => 'MultiStatus',
'title' => 'Status',
'component' => './Stv/Studentenverwaltung/Details/MultiStatus.js',
'config' => [
'abbrecherStgl' => $this->permissionlib->isBerechtigt('admin'),
'abbrecherStud' => $this->permissionlib->isBerechtigt('admin')
'changeStatusToAbbrecherStgl' => $this->permissionlib->isBerechtigt('admin'),
'changeStatusToAbbrecherStud' => $this->permissionlib->isBerechtigt('admin'),
'changeStatusToUnterbrecher' => $this->permissionlib->isBerechtigt('admin'),
'changeStatusToDiplomand' => $this->permissionlib->isBerechtigt('admin'),
'changeStatusToAbsolvent' => $this->permissionlib->isBerechtigt('admin')
]
];
/* $result['status'] = [
'title' => 'Status',
'component' => './Stv/Studentenverwaltung/Details/Status.js',
'config' => [
'abbrecherStgl' => $this->permissionlib->isBerechtigt('admin'),
'abbrecherStud' => $this->permissionlib->isBerechtigt('admin')
]
];*/
Events::trigger('stv_conf_students', function & () use (&$result) {
return $result;
@@ -110,4 +113,96 @@ class Config extends FHC_Controller
$this->outputJsonSuccess($result);
}
protected function kontoColumns()
{
return [
'buchungsdatum' => [
'field' => "buchungsdatum",
'title' => $this->p->t('konto', 'buchungsdatum')
],
'buchungstext' => [
'field' => "buchungstext",
'title' => $this->p->t('konto', 'buchungstext')
],
'betrag' => [
'field' => "betrag",
'title' => $this->p->t('konto', 'betrag')
],
'studiensemester_kurzbz' => [
'field' => "studiensemester_kurzbz",
'title' => $this->p->t('lehre', 'studiensemester')
],
'buchungstyp_kurzbz' => [
'field' => "buchungstyp_kurzbz",
'title' => $this->p->t('konto', 'buchungstyp'),
'visible' => false
],
'buchungsnr' => [
'field' => "buchungsnr",
'title' => $this->p->t('konto', 'buchungsnr'),
'visible' => false
],
'insertvon' => [
'field' => "insertvon",
'title' => $this->p->t('global', 'insertvon'),
'visible' => false
],
'insertamum' => [
'field' => "insertamum",
'title' => $this->p->t('global', 'insertamum'),
'visible' => false
],
'kuerzel' => [
'field' => "kuerzel",
'title' => $this->p->t('lehre', 'studiengang'),
'visible' => false
],
'anmerkung' => [
'field' => "anmerkung",
'title' => $this->p->t('global', 'anmerkung')
],
'actions' => [
'title' => $this->p->t('global', 'actions'),
'frozen' => true
]
];
}
protected function kontoColumnsMultiPerson()
{
return [
'person_id' => [
'field' => "person_id",
'title' => $this->p->t('person', 'person_id')
],
'anrede' => [
'field' => "anrede",
'title' => $this->p->t('person', 'anrede'),
'visible' => false
],
'titelpost' => [
'field' => "titelpost",
'title' => $this->p->t('person', 'titelpost'),
'visible' => false
],
'titelpre' => [
'field' => "titelpre",
'title' => $this->p->t('person', 'titelpre'),
'visible' => false
],
'vorname' => [
'field' => "vorname",
'title' => $this->p->t('person', 'vorname')
],
'vornamen' => [
'field' => "vornamen",
'title' => $this->p->t('person', 'vornamen'),
'visible' => false
],
'nachname' => [
'field' => "nachname",
'title' => $this->p->t('person', 'nachname')
]
] + $this->kontoColumns();
}
}
@@ -2,6 +2,8 @@
if (! defined('BASEPATH')) exit('No direct script access allowed');
// TODO(chris): Prestudent status missing
class Students extends FHC_Controller
{
public function __construct()
@@ -320,6 +322,8 @@ class Students extends FHC_Controller
break;
}
$this->addFilter($studiensemester_kurzbz);
$this->outputJson([]);
}
@@ -426,6 +430,8 @@ class Students extends FHC_Controller
}
$this->addFilter($studiensemester_kurzbz);
$result = $this->PrestudentModel->loadWhere($where);
if (isError($result)) {
@@ -497,6 +503,8 @@ class Students extends FHC_Controller
$this->PrestudentModel->addSelect('p.zugangscode');
$this->PrestudentModel->addSelect('p.bpk');
$this->addFilter($studiensemester_kurzbz);
$result = $this->PrestudentModel->loadWhere([
'tbl_prestudent.prestudent_id' => $prestudent_id
]);
@@ -570,6 +578,8 @@ class Students extends FHC_Controller
$this->PrestudentModel->addSelect('p.zugangscode');
$this->PrestudentModel->addSelect('p.bpk');
$this->addFilter($studiensemester_kurzbz);
$result = $this->PrestudentModel->loadWhere([
's.student_uid' => $student_uid
]);
@@ -643,6 +653,8 @@ class Students extends FHC_Controller
$this->PrestudentModel->addSelect('p.zugangscode');
$this->PrestudentModel->addSelect('p.bpk');
$this->addFilter($studiensemester_kurzbz);
$result = $this->PrestudentModel->loadWhere([
'p.person_id' => $person_id
]);
@@ -654,4 +666,45 @@ class Students extends FHC_Controller
$this->outputJson(getData($result) ?: []);
}
}
/**
* Adds additional filters to the query
*
* @param string $studiensemester_kurzbz
*
* @return void
*/
protected function addFilter($studiensemester_kurzbz)
{
$filter = $this->input->get('filter');
if (isset($filter['konto_count_0'])) {
$bt = $this->PrestudentModel->escape($filter['konto_count_0']);
$stdsem = $this->PrestudentModel->escape($studiensemester_kurzbz);
$this->PrestudentModel->db->where('(
SELECT count(*)
FROM public.tbl_konto
WHERE person_id=tbl_prestudent.person_id
AND buchungstyp_kurzbz=' . $bt . '
AND studiensemester_kurzbz=' . $stdsem . '
) =', 0);
$this->PrestudentModel->db->where('get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL) !=', 'Incoming');
}
if (isset($filter['konto_missing_counter'])) {
$bt = $this->PrestudentModel->escape($filter['konto_missing_counter']);
$stg = '';
if ($this->variablelib->getVar('kontofilterstg') == 'true')
$stg = ' AND studiengang_kz=tbl_prestudent.studiengang_kz';
$bt = $bt == 'alle' ? '' : ' AND buchungstyp_kurzbz=' . $bt;
$this->PrestudentModel->db->where('(
SELECT sum(betrag)
FROM public.tbl_konto
WHERE person_id=tbl_prestudent.person_id' .
$bt .
$stg . '
) !=', 0);
}
}
}
+2 -2
View File
@@ -84,8 +84,8 @@ class Konto_model extends DB_Model
{
$this->db->where('buchungsnr_verweis', $id);
if ($this->db->count_all_results($this->dbTable))
return error('Bitte zuerst die zugeordneten Buchungen loeschen');
return parent::delete($id, 42);
return error('Bitte zuerst die zugeordneten Buchungen loeschen', 42);
return parent::delete($id);
}
/**
+4
View File
@@ -104,3 +104,7 @@ html {
background-color: #f8d7da!important;
border-color: #f5c2c7!important;
}
.has-filter .fa-filter {
color: var(--bs-success);
}
+2
View File
@@ -1,5 +1,7 @@
import filter from './stv/filter.js';
import konto from './stv/konto.js';
export default {
filter,
konto
};
+10
View File
@@ -0,0 +1,10 @@
export default {
getStg() {
return this.$fhcApi.get('api/frontend/v1/stv/filter/getStg');
},
setStg(studiengang_kz) {
return this.$fhcApi.post('api/frontend/v1/stv/filter/setStg', {
studiengang_kz
});
}
};
+3 -1
View File
@@ -1,5 +1,7 @@
import Search from "./search.js";
import stv from "../../api/stv.js";
export default {
"Search": Search
"Search": Search,
stv
};
@@ -190,14 +190,14 @@ export default {
<div class="stv">
<header class="navbar navbar-expand-lg navbar-dark bg-dark flex-md-nowrap p-0 shadow">
<a class="navbar-brand col-md-4 col-lg-3 col-xl-2 me-0 px-3" :href="stvRoot">FHC 4.0</a>
<button class="navbar-toggler d-md-none m-1 collapsed" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
<button class="navbar-toggler d-md-none m-1 collapsed" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" :aria-label="$p.t('ui/toggle_nav')"><span class="navbar-toggler-icon"></span></button>
<core-searchbar :searchoptions="searchbaroptions" :searchfunction="searchfunction" class="searchbar w-100"></core-searchbar>
</header>
<div class="container-fluid overflow-hidden">
<div class="row h-100">
<nav id="sidebarMenu" class="bg-light offcanvas offcanvas-start col-md p-md-0 h-100">
<div class="offcanvas-header justify-content-end px-1 d-md-none">
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" :aria-label="$p.t('ui/schliessen')"></button>
</div>
<stv-verband @select-verband="onSelectVerband" class="col" style="height:0%"></stv-verband>
<stv-studiensemester :default="defaultSemester" @changed="studiensemesterChanged"></stv-studiensemester>
@@ -3,7 +3,7 @@ import FormInput from "../../../Form/Input.js";
import KontoNew from "./Konto/New.js";
import KontoEdit from "./Konto/Edit.js";
// TODO(chris): Phrasen
const LOCAL_STORAGE_ID_FILTER = 'stv_details_konto_2024-01-11_filter';
export default {
components: {
@@ -52,130 +52,46 @@ export default {
}
},
tabulatorColumns() {
let columns = [];
if (Array.isArray(this.modelValue)) {
columns.push({
field: "person_id",
title: "Person ID"
});
columns.push({
field: "anrede",
title: "Anrede",
visible: false
});
columns.push({
field: "titelpost",
title: "Titelpost",
visible: false
});
columns.push({
field: "titelpre",
title: "Titelpre",
visible: false
});
columns.push({
field: "vorname",
title: "Vorname"
});
columns.push({
field: "vornamen",
title: "Vornamen",
visible: false
});
columns.push({
field: "nachname",
title: "Nachname"
});
}
const columns = { ...this.config.columns };
if (!columns.actions)
columns.actions = {
title: '',
frozen: true
};
columns.actions.formatter = cell => {
let container = document.createElement('div');
container.className = "d-flex gap-2";
columns = [...columns, ...[
{
field: "buchungsdatum",
title: "Buchungsdatum"
},
{
field: "buchungstext",
title: "Buchungstext"
},
{
field: "betrag",
title: "Betrag"
},
{
field: "studiensemester_kurzbz",
title: "StSem"
},
{
field: "buchungstyp_kurzbz",
title: "Typ",
visible: false
},
{
field: "buchungsnr",
title: "Buchungs Nr",
visible: false
},
{
field: "insertvon",
title: "Angelegt von",
visible: false
},
{
field: "insertamum",
title: "Anlagedatum",
visible: false
},
{
field: "kuerzel",
title: "Studiengang",
visible: false
},
{
field: "anmerkung",
title: "Anmerkung"
}
]];
let button = document.createElement('button');
button.className = 'btn btn-outline-secondary';
button.innerHTML = '<i class="fa fa-edit"></i>';
button.addEventListener('click', () =>
this.$refs.edit.open(cell.getData())
);
container.append(button);
columns = [...columns, ...this.config.additionalCols];
button = document.createElement('button');
button.className = 'btn btn-outline-secondary';
button.innerHTML = '<i class="fa fa-trash"></i>';
button.addEventListener('click', evt => {
evt.stopPropagation();
this.$fhcAlert
.confirmDelete()
.then(result => result ? cell.getData().buchungsnr : Promise.reject({handled:true}))
.then(this.$fhcApi.factory.stv.konto.delete)
.then(() => {
// TODO(chris): deleting a child also removes the siblings!
//cell.getRow().delete();
this.reload();
})
.catch(this.$fhcAlert.handleSystemError);
});
container.append(button);
columns.push({
title: 'Actions',
formatter: cell => {
let container = document.createElement('div');
container.className = "d-flex gap-2";
return container;
};
let button = document.createElement('button');
button.className = 'btn btn-outline-secondary';
button.innerHTML = '<i class="fa fa-edit"></i>';
button.addEventListener('click', () =>
this.$refs.edit.open(cell.getData())
);
container.append(button);
button = document.createElement('button');
button.className = 'btn btn-outline-secondary';
button.innerHTML = '<i class="fa fa-trash"></i>';
button.addEventListener('click', evt => {
evt.stopPropagation();
this.$fhcAlert
.confirmDelete()
.then(result => result ? cell.getData().buchungsnr : Promise.reject({handled:true}))
.then(this.$fhcApi.factory.stv.konto.delete)
.then(() => {
// TODO(chris): deleting a child also removes the siblings!
//cell.getRow().delete();
this.reload();
})
.catch(this.$fhcAlert.handleSystemError);
});
container.append(button);
return container;
},
frozen: true
});
return columns;
return Object.values(columns);
},
tabulatorOptions() {
return this.$fhcApi.factory.stv.konto.tabulatorConfig({
@@ -214,7 +130,7 @@ export default {
})
.then(result => result.data)
.then(this.updateData)
.then(() => 'Daten wurden gespeichert')
.then(() => this.$p.t('ui/gespeichert'))
.then(this.$fhcAlert.alertSuccess)
.catch(this.$fhcAlert.handleSystemError);
},
@@ -250,11 +166,24 @@ export default {
'_blank'
);
}
},
setFilter(type) {
if (type == 'open')
window.localStorage.setItem(LOCAL_STORAGE_ID_FILTER, this.filter ? 1 : 0);
else if (type == 'current_stg')
this.$fhcApi.factory
.stv.filter.setStg(this.studiengang_kz)
.catch(this.$fhcAlert.handleSystemError);
this.$nextTick(this.$refs.table.reloadTable);
}
},
created() {
// TODO(chris): persist filter + studiengang_kz
// TODO(chris): studiengang_kz in variablelib
this.filter = window.localStorage.getItem(LOCAL_STORAGE_ID_FILTER) == 1;
this.$fhcApi.factory
.stv.filter.getStg()
.then(result => this.studiengang_kz = result.data)
.catch(this.$fhcAlert.handleSystemError);
},
template: `
<div class="stv-details-konto h-100 d-flex flex-column">
@@ -263,9 +192,9 @@ export default {
<form-input
container-class="form-switch"
type="checkbox"
label="Nur offene anzeigen"
:label="$p.t('stv/konto_filter_open')"
v-model="filter"
@update:model-value="() => $nextTick($refs.table.reloadTable)"
@update:model-value="setFilter('open')"
>
</form-input>
</div>
@@ -273,10 +202,10 @@ export default {
<form-input
container-class="form-switch"
type="checkbox"
label="Nur aktuellen Stg anzeigen"
:label="$p.t('stv/konto_filter_current_stg')"
v-model="studiengang_kz_intern"
:disabled="!stg_kz"
@update:model-value="() => $nextTick($refs.table.reloadTable)"
@update:model-value="setFilter('current_stg')"
>
</form-input>
</div>
@@ -288,7 +217,7 @@ export default {
:tabulator-options="tabulatorOptions"
reload
new-btn-show
new-btn-label="Buchung"
:new-btn-label="$p.t('konto/buchung')"
:new-btn-disabled="stg_kz === ''"
@click:new="actionNew"
>
@@ -308,7 +237,7 @@ export default {
@click="actionCounter(selected)"
:disabled="!selected.length"
>
Gegenbuchen
{{ $p.t('stv/konto_counter') }}
</button>
</div>
<button
@@ -317,7 +246,7 @@ export default {
@click="downloadPdf(selected)"
:disabled="!selected.length"
>
<i class="fa fa-download"></i> Zahlungsbestaetigung
<i class="fa fa-download"></i> {{ $p.t('stv/konto_payment_confirmation') }}
</button>
</template>
</core-filter-cmpt>
@@ -3,7 +3,6 @@ import CoreForm from "../../../../Form/Form.js";
import FormValidation from "../../../../Form/Validation.js";
import FormInput from "../../../../Form/Input.js";
// TODO(chris): Phrasen
export default {
components: {
@@ -40,7 +39,7 @@ export default {
this.$emit('saved', result.data);
this.loading = false;
this.$refs.modal.hide();
this.$fhcAlert.alertSuccess('Daten wurden gespeichert');
this.$fhcAlert.alertSuccess(this.$p.t('ui/gespeichert'));
})
.catch(error => {
this.$fhcAlert.handleSystemError(error);
@@ -66,21 +65,21 @@ export default {
v-if="config.showBuchungsnr"
v-model="data.buchungsnr"
name="buchungsnr"
label="Buchungsnr"
:label="$p.t('konto/buchungsnr')"
disabled
>
</form-input>
<form-input
v-model="data.betrag"
name="betrag"
label="Betrag"
:label="$p.t('konto/betrag')"
>
</form-input>
<form-input
type="DatePicker"
v-model="data.buchungsdatum"
name="buchungsdatum"
label="Buchungsdatum"
:label="$p.t('konto/buchungsdatum')"
:enable-time-picker="false"
auto-apply
>
@@ -88,21 +87,21 @@ export default {
<form-input
v-model="data.buchungstext"
name="buchungstext"
label="Buchungstext"
:label="$p.t('konto/buchungstext')"
>
</form-input>
<form-input
v-if="config.showMahnspanne"
v-model="data.mahnspanne"
name="mahnspanne"
label="Mahnspanne"
:label="$p.t('konto/mahnspanne')"
>
</form-input>
<form-input
type="select"
v-model="data.buchungstyp_kurzbz"
name="buchungstyp_kurzbz"
label="Typ"
:label="$p.t('konto/buchungstyp')"
>
<option v-for="typ in lists.buchungstypen" :key="typ.buchungstyp_kurzbz" :value="typ.buchungstyp_kurzbz" :class="typ.aktiv ? '' : 'text-decoration-line-through text-muted'">
{{ typ.beschreibung }}
@@ -112,7 +111,7 @@ export default {
type="select"
v-model="data.studiensemester_kurzbz"
name="studiensemester_kurzbz"
label="Studiensemester"
:label="$p.t('lehre/studiensemester')"
>
<option v-for="sem in lists.studiensemester" :key="sem.studiensemester_kurzbz" :value="sem.studiensemester_kurzbz">
{{ sem.studiensemester_kurzbz }}
@@ -122,7 +121,7 @@ export default {
type="select"
v-model="data.studiengang_kz"
name="studiengang_kz"
label="Studiengang"
:label="$p.t('lehre/studiengang')"
>
<option v-for="stg in lists.stgs" :key="stg.studiengang_kz" :value="stg.studiengang_kz">
{{ stg.kuerzel }}
@@ -132,13 +131,13 @@ export default {
v-if="config.showCreditpoints"
v-model="data.credit_points"
name="credit_points"
label="Credit Points"
:label="$p.t('konto/credit_points')"
>
</form-input>
<form-input
v-model="data.zahlungsreferenz"
name="zahlungsreferenz"
label="Zahlungsreferenz"
:label="$p.t('konto/reference')"
disabled
>
</form-input>
@@ -146,18 +145,18 @@ export default {
type="textarea"
v-model="data.anmerkung"
name="anmerkung"
label="Anmerkung"
:label="$p.t('global/anmerkung')"
>
</form-input>
</fieldset>
<template #title>
Edit Buchung #{{data.buchungsnr}}
{{ $p.t('stv/konto_title_edit', data) }}
</template>
<template #footer>
<button type="submit" class="btn btn-primary" :disabled="loading">
<i v-if="loading" class="fa fa-spinner fa-spin"></i>
Speichern
{{ $p.t('ui/speichern') }}
</button>
</template>
</bs-modal>
@@ -4,7 +4,6 @@ import CoreForm from "../../../../Form/Form.js";
import FormValidation from "../../../../Form/Validation.js";
import FormInput from "../../../../Form/Input.js";
// TODO(chris): Phrasen
export default {
components: {
@@ -74,7 +73,7 @@ export default {
this.$emit('saved', result.data);
this.loading = false;
this.$refs.modal.hide();
this.$fhcAlert.alertSuccess('Daten wurden gespeichert');
this.$fhcAlert.alertSuccess(this.$p.t('ui/gespeichert'));
})
.catch(error => {
if (error)
@@ -125,7 +124,7 @@ export default {
type="select"
v-model="data.buchungstyp_kurzbz"
name="buchungstyp_kurzbz"
label="Typ"
:label="$p.t('konto/buchungstyp')"
@update:model-value="checkDefaultBetrag"
>
<option v-for="typ in activeBuchungstypen" :key="typ.buchungstyp_kurzbz" :value="typ.buchungstyp_kurzbz" :class="typ.aktiv ? '' : 'text-decoration-line-through text-muted'">
@@ -135,14 +134,14 @@ export default {
<form-input
v-model="data.betrag"
name="betrag"
label="Betrag"
:label="$p.t('konto/betrag')"
>
</form-input>
<form-input
type="DatePicker"
v-model="data.buchungsdatum"
name="buchungsdatum"
label="Buchungsdatum"
:label="$p.t('konto/buchungsdatum')"
:enable-time-picker="false"
auto-apply
>
@@ -150,21 +149,21 @@ export default {
<form-input
v-model="data.buchungstext"
name="buchungstext"
label="Buchungstext"
:label="$p.t('konto/buchungstext')"
>
</form-input>
<form-input
v-if="config.showMahnspanne"
v-model="data.mahnspanne"
name="mahnspanne"
label="Mahnspanne"
:label="$p.t('konto/mahnspanne')"
>
</form-input>
<form-input
type="select"
v-model="data.studiensemester_kurzbz"
name="studiensemester_kurzbz"
label="Studiensemester"
:label="$p.t('lehre/studiensemester')"
>
<option v-for="sem in reversedSems" :key="sem.studiensemester_kurzbz" :value="sem.studiensemester_kurzbz">
{{ sem.studiensemester_kurzbz }}
@@ -174,28 +173,29 @@ export default {
v-if="config.showCreditpoints"
v-model="data.credit_points"
name="credit_points"
label="Credit Points"
:label="$p.t('konto/credit_points')"
>
</form-input>
<form-input
type="textarea"
v-model="data.anmerkung"
name="anmerkung"
label="Anmerkung"
:label="$p.t('global/anmerkung')"
>
</form-input>
</fieldset>
<template #title>
New Buchung
<template v-if="personIds.length > 1">
({{ personIds.length }} Studenten)
</template>
{{ $p.t(
'stv',
personIds.length > 1 ? 'konto_title_new_multi' : 'konto_title_new',
{ x: personIds.length }
) }}
</template>
<template #footer>
<button type="submit" class="btn btn-primary" :disabled="loading">
<i v-if="loading" class="fa fa-spinner fa-spin"></i>
Speichern
{{ $p.t('ui/speichern') }}
</button>
</template>
</bs-modal>
@@ -11,7 +11,7 @@ export default {
<div class="stv-details-details h-100 pb-3">
<div class="col-12 pb-3">
<legend>MultiStatus</legend>
<legend>Status</legend>
<TblMultiStatus :modelValue="modelValue"></TblMultiStatus>
</div>
</div>
@@ -2,15 +2,13 @@ import {CoreRESTClient} from '../../../../RESTClient.js';
import FormForm from '../../../Form/Form.js';
import FormInput from '../../../Form/Input.js';
import TblHistory from "./Prestudent/History.js";
import TblStatus from "./Prestudent/Status.js";
export default {
components: {
CoreRESTClient,
FormForm,
FormInput,
TblHistory,
TblStatus
TblHistory
},
inject: {
lists: {
@@ -349,7 +349,7 @@ export default{
});
},
actionConfirmDialogue(data, statusgrund, statusText){
//this.hideModal('addMultiStatus2');
this.hideModal('addMultiStatus2');
this.actionButton = statusgrund;
this.actionStatusText = statusText;
@@ -360,7 +360,7 @@ export default{
this.$refs.askForAusbildungssemester.show();
},
changeStatusToAbbrecherStgl(prestudentIds){
this.hideModal('confirmStatusAction2');
this.hideModal('confirmStatusAction');
let abbruchData =
{
status_kurzbz: 'Abbrecher',
@@ -445,6 +445,7 @@ export default{
this.newArray = this.updateData.map(objekt => ({ ...objekt, ...deltaData}));
console.log("in changeStatusToDiplomand" + prestudentIds);
this.hideModal('addMultiStatus2');
this.addNewStatus(prestudentIds);
},
changeStatusToAbsolvent(prestudentIds){
@@ -459,6 +460,7 @@ export default{
this.newArray = this.updateData.map(objekt => ({ ...objekt, ...deltaData}));
console.log("in changeStatusToAbsolvent" + prestudentIds);
this.hideModal('addMultiStatus2');
this.addNewStatus(prestudentIds);
},
addNewStatus(prestudentIds){
@@ -602,12 +604,6 @@ export default{
reload(){
this.$refs.table.reloadTable(); //bei multiactions not working
},
reloadLast(prestudent_id){
console.log("prestudent_id: " + prestudent_id);
// this.$refs.table.tabulator.setData('api/frontend/v1/stv/Status/getHistoryPrestudent/' + prestudent_id);
// window.location.href = "https://c3p0.ma0068.technikum-wien.at/fhcomplete/index.ci.php/studentenverwaltung/prestudent/" + prestudent_id + "/multistatus";
},
hideModal(modalRef){
this.$refs[modalRef].hide();
},
@@ -656,22 +652,6 @@ export default{
mounted(){},
template: `
<div class="stv-list h-100 pt-3">
PersonId(s): {{personIds}}
||
PrestudentId(s): {{prestudentIds}}
<hr>
<!-- {{statusData}}
<hr>
{{modelValue}}
<hr>
{{updateData}}-->
<!--Modal: Add New Status-->
<BsModal ref="newStatusModal">
@@ -682,7 +662,7 @@ export default{
<div class="row mb-3">
<label for="status_kurzbz" class="form-label col-sm-4">{{$p.t('lehre', 'status_rolle')}}</label>
<div class="col-sm-6">
<!--<form-input type="text" :readonly="readonly" class="form-control" id="status_kurzbz" v-model="statusData['status_kurzbz']">-->
<form-input
required
v-model="statusData['status_kurzbz']"
@@ -1051,6 +1031,50 @@ export default{
</template>
</BsModal>
<BsModal ref="addMultiStatus2" id="addMultiStatus2">
<template #title>Status ändern zu</template>
<template #default>
<button type="button" class="btn btn-primary d-block mb-2" data-bs-toggle="collapse" data-bs-target="#submenu1">
Abbrecher
</button>
<div class="collapse" id="submenu1">
<button type="button" class="btn btn-light d-block mb-2" @click="actionConfirmDialogue(updateData, 'abbrecherStgl', 'Abbrecher')">durch Stgl</button>
<button type="button" class="btn btn-light d-block mb-2" @click="actionConfirmDialogue(updateData, 'abbrecherStud','Abbrecher')">durch Student</button>
</div>
<button type="button" class="btn btn-primary d-block mb-2" @click="actionConfirmDialogue(updateData, 'unterbrecher','Unterbrecher')">
Unterbrecher
</button>
<button type="button" class="btn btn-primary d-block mb-2" data-bs-toggle="collapse" data-bs-target="#submenu2">
Student
</button>
<div class="collapse" id="submenu2">
<button type="button" class="btn btn-light d-block mb-2" @click="actionConfirmDialogue(updateData, 'student','Student')">Student</button>
<button type="button" class="btn btn-light d-block mb-2" @click="actionConfirmDialogue(updateData, 'student','Wiederholer')">Wiederholer</button>
</div>
<button type="button" class="btn btn-primary d-block mb-2" @click="changeStatusToDiplomand(prestudentIds)">
Diplomand
</button>
<button type="button" class="btn btn-primary d-block mb-2" @click="changeStatusToAbsolvent(prestudentIds)">
Absolvent
</button>
</template>
<template #footer>
<div v-if="actionButton=='abbrecherStgl'">
<button ref="Close" type="button" class="btn btn-primary" @click="changeStatusToAbbrecherStgl(prestudentIds)">OK</button>
</div>
<div v-if="actionButton=='abbrecherStud'">
<button ref="Close" type="button" class="btn btn-primary" @click="changeStatusToAbbrecherStud(prestudentIds)">OK</button>
</div>
<div v-if="actionButton=='unterbrecher'">
<button ref="Close" type="button" class="btn btn-primary" @click="changeStatusToUnterbrecher(prestudentIds)">OK</button>
</div>
</template>
</BsModal>
<!--Modal: askForAusbildungssemester-->
<BsModal ref="askForAusbildungssemester">
<template #title>{{$p.t('lehre', 'status_edit')}}</template>
@@ -1072,8 +1096,7 @@ export default{
>
</form-input>
</div>
</div>
</div>
</template>
<template #footer>
@@ -1137,287 +1160,19 @@ export default{
>
<template #actions="{updateData2}">
<!-- Version1 -->
<!-- <div class="btn-group">
&lt;!&ndash; Hauptbutton &ndash;&gt;
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
Status Ändern
</button>
&lt;!&ndash; Dropdown-Menü &ndash;&gt;
<ul class="dropdown-menu">
&lt;!&ndash; Schleife für fünf Unterbuttons &ndash;&gt;
&lt;!&ndash; Jeder Unterbutton hat zwei weitere Unterbuttons &ndash;&gt;
<li class="dropdown-submenu">
<a class="dropdown-item dropdown-toggle" href="#">Abbrecher</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Unterbutton 1-1</a></li>
<li><a class="dropdown-item" href="#">Unterbutton 1-2</a></li>
</ul>
</li>
<li class="dropdown-submenu">
<a class="dropdown-item dropdown-toggle" href="#">Unterbrecher</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Unterbutton 2-1</a></li>
<li><a class="dropdown-item" href="#">Unterbutton 2-2</a></li>
</ul>
</li>
<li class="dropdown-submenu">
<a class="dropdown-item dropdown-toggle" href="#">Student</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Unterbutton 3-1</a></li>
<li><a class="dropdown-item" href="#">Unterbutton 3-2</a></li>
</ul>
</li>
<li class="dropdown-submenu">
<a class="dropdown-item dropdown-toggle" href="#">Diplomand</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Unterbutton 4-1</a></li>
<li><a class="dropdown-item" href="#">Unterbutton 4-2</a></li>
</ul>
</li>
<li class="dropdown-submenu">
<a class="dropdown-item dropdown-toggle" href="#">Absolvent</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Unterbutton 5-1</a></li>
<li><a class="dropdown-item" href="#">Unterbutton 5-2</a></li>
</ul>
</li>
</ul>
</div>-->
<!-- Version2 -->
<!-- <div class="btn-group">
&lt;!&ndash; Hauptbutton &ndash;&gt;
<button type="button" class="btn btn-primary" data-bs-toggle="offcanvas" data-bs-target="#offcanvasMenu">
Version 2
</button>
</div>-->
<!-- Offcanvas-Menü -->
<!-- <div class="offcanvas offcanvas-start" tabindex="-1" id="offcanvasMenu" aria-labelledby="offcanvasMenuLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasMenuLabel">Untermenü</h5>
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
&lt;!&ndash; Untermenü-Buttons &ndash;&gt;
<button type="button" class="btn btn-secondary d-block mb-2">Unterbutton 1-1</button>
<button type="button" class="btn btn-secondary d-block mb-2">Unterbutton 1-2</button>
<button type="button" class="btn btn-secondary d-block mb-2">Unterbutton 2-1</button>
<button type="button" class="btn btn-secondary d-block mb-2">Unterbutton 2-2</button>
<button type="button" class="btn btn-secondary d-block mb-2">Unterbutton 3-1</button>
<button type="button" class="btn btn-secondary d-block mb-2">Unterbutton 3-2</button>
<button type="button" class="btn btn-secondary d-block mb-2">Unterbutton 4-1</button>
<button type="button" class="btn btn-secondary d-block mb-2">Unterbutton 4-2</button>
<button type="button" class="btn btn-secondary d-block mb-2">Unterbutton 5-1</button>
<button type="button" class="btn btn-secondary d-block mb-2">Unterbutton 5-2</button>
</div>
</div>-->
<!-- Hauptbutton zum Öffnen des Modals -->
<!--TODO(MANU) use bs template addMultiStatus-->
<!--<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#mainModal">
Status Ändern(3)
</button>-->
<!-- Modal für Hauptbuttons und Untermenü-Buttons -->
<!--<div class="modal fade" id="mainModal" tabindex="-1" aria-labelledby="mainModalLabel" aria-hidden="true" ref="addMultiStatus2">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="mainModalLabel">Status ändern zu</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
&lt;!&ndash; Liste der Hauptbuttons &ndash;&gt;
<button type="button" class="btn btn-primary d-block mb-2" data-bs-toggle="collapse" data-bs-target="#submenu1">
Abbrecher
</button>
<div class="collapse" id="submenu1">
<button type="button" class="btn btn-light d-block mb-2" @click="actionConfirmDialogue(updateData, 'abbrecherStgl', 'Abbrecher')">durch Stgl</button>
<button type="button" class="btn btn-light d-block mb-2" @click="actionConfirmDialogue(updateData, 'abbrecherStud','Abbrecher')">durch Student</button>
</div>
<button type="button" class="btn btn-primary d-block mb-2" @click="actionConfirmDialogue(updateData, 'unterbrecher','Unterbrecher')">
Unterbrecher
</button>
<button type="button" class="btn btn-primary d-block mb-2" data-bs-toggle="collapse" data-bs-target="#submenu2">
Student
</button>
<div class="collapse" id="submenu2">
<button type="button" class="btn btn-light d-block mb-2" @click="actionConfirmDialogue(updateData, 'student','Student')">Student</button>
<button type="button" class="btn btn-light d-block mb-2" @click="actionConfirmDialogue(updateData, 'student','Wiederholer')">Wiederholer</button>
</div>
<button type="button" class="btn btn-primary d-block mb-2" @click="changeStatusToDiplomand(prestudentIds)">
Diplomand
</button>
<button type="button" class="btn btn-primary d-block mb-2" @click="changeStatusToAbsolvent(prestudentIds)">
Absolvent
</button>
</div>
</div>
</div>
</div>-->
<button
class="btn btn-outline-primary"
@click="actionChangeStatus(selected)"
> Status Ändern
</button>
<button
class="btn btn-outline-secondary"
@click="actionConfirmDialogue(updateData, 'abbrecherStgl', 'Abbrecher')"
>
Abbrecher Stgl
</button>
<button
class="btn btn-outline-secondary"
@click="actionConfirmDialogue(updateData, 'abbrecherStud','Abbrecher')"
>
Abbrecher Stud
</button>
<button
class="btn btn-outline-secondary"
@click="actionConfirmDialogue(updateData, 'unterbrecher','Unterbrecher')"
>
Unterbrecher
</button>
<button
class="btn btn-outline-secondary"
@click="actionConfirmDialogue(updateData, 'student','Student')"
>
Student
</button>
<button
class="btn btn-outline-secondary"
@click="actionConfirmDialogue(updateData, 'student','Wiederholer')"
>
Wiederholer
</button>
<button
class="btn btn-outline-secondary"
@click="changeStatusToDiplomand(prestudentIds)"
>
Diplomand
</button>
<button
class="btn btn-outline-secondary"
@click="changeStatusToAbsolvent(prestudentIds)"
>
Absolvent
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addMultiStatus2">
Status Ändern
</button>
</template>
</core-filter-cmpt>
<div
v-if="this.modelValue.length"
ref="buttonsStatusMulti"
v-if="this.modelValue.length"
ref="buttonsStatusMulti"
>
<button
class="btn btn-outline-secondary"
@click="actionConfirmDialogue(updateData, 'abbrecherStgl', 'Abbrecher')"
>
Abbrecher Stgl
</button>
<button
class="btn btn-outline-secondary"
@click="actionConfirmDialogue(updateData, 'abbrecherStud','Abbrecher')"
>
Abbrecher Stud
</button>
<button
class="btn btn-outline-secondary"
@click="actionConfirmDialogue(updateData, 'unterbrecher','Unterbrecher')"
>
Unterbrecher
</button>
<button
class="btn btn-outline-secondary"
@click="actionConfirmDialogue(updateData, 'student','Student')"
>
Student
</button>
<button
class="btn btn-outline-secondary"
@click="changeStatusToDiplomand(prestudentIds)"
>
Diplomand
</button>
<button
class="btn btn-outline-secondary"
@click="changeStatusToAbsolvent(prestudentIds)"
>
Absolvent
</button>
<!-- <template #actions="{updateData}">
<button
class="btn btn-outline-primary"
@click="actionChangeStatus(selected)"
> Status Ändern
</button>
<button
class="btn btn-outline-secondary"
@click="actionConfirmDialogue(updateData)"
>
Abbrecher Stgl
</button>
<button
class="btn btn-outline-secondary"
@click="actionConfirmDialogue(selected)"
>
Abbrecher Stud
</button>
<button
class="btn btn-outline-secondary"
@click="actionConfirmDialogue(selected)"
>
Unterbrecher
</button>
<button
class="btn btn-outline-secondary"
@click="actionConfirmDialogue(selected)"
>
Student
</button>
<button
class="btn btn-outline-secondary"
@click="actionConfirmDialogue(selected)"
>
Wiederholer
</button>
<button
class="btn btn-outline-secondary"
@click="actionConfirmDialogue(selected)"
>
Diplomand
</button>
</template>-->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addMultiStatus2">
Status Ändern
</button>
</div>
</div>`
@@ -1,858 +0,0 @@
import {CoreFilterCmpt} from "../../../../filter/Filter.js";
import BsModal from "../../../../Bootstrap/Modal.js";
import FormForm from '../../../../Form/Form.js';
import FormInput from '../../../../Form/Input.js';
export default{
components: {
CoreFilterCmpt,
BsModal,
FormForm,
FormInput,
},
inject: {
defaultSemester: {
from: 'defaultSemester',
},
hasPermissionToSkipStatusCheck: {
from: 'hasPermissionToSkipStatusCheck',
default: false
},
hasPrestudentPermission: {
from: 'hasPrestudentPermission',
default: false
},
hasAssistenzPermission: {
from: 'hasAssistenzPermission',
default: false
},
hasAdminPermission: {
from: 'hasAdminPermission',
default: false
},
hasAssistenzPermissionForStgs: {
from: 'hasAssistenzPermissionForStgs',
default: false
},
hasSchreibrechtAss: {
from: 'hasSchreibrechtAss',
default: false
}
},
props: {
prestudent_id: String,
studiengang_kz: String
},
data() {
return {
tabulatorOptions: {
ajaxURL: 'api/frontend/v1/stv/Status/getHistoryPrestudent/' + this.prestudent_id,
ajaxRequestFunc: this.$fhcApi.get,
ajaxResponse: (url, params, response) => response.data,
columns: [
{title: "Kurzbz", field: "status_kurzbz", tooltip: true},
{title: "StSem", field: "studiensemester_kurzbz"},
{title: "Sem", field: "ausbildungssemester"},
{title: "Lehrverband", field: "lehrverband"},
{title: "Datum", field: "format_datum"},
{title: "Studienplan", field: "bezeichnung"},
{title: "BestätigtAm", field: "format_bestaetigtam"},
{title: "AbgeschicktAm", field: "format_bewerbung_abgeschicktamum"},
{title: "Statusgrund", field: "statusgrund_kurzbz", visible: false},
{title: "Organisationsform", field: "orgform_kurzbz", visible: false},
{title: "PrestudentInId", field: "prestudent_id", visible: false},
{title: "StudienplanId", field: "studienplan_id", visible: false},
{title: "Anmerkung", field: "anmerkung", visible: false},
{title: "BestätigtVon", field: "bestaetigtvon", visible: false},
{title: "InsertAmUm", field: "format_insertamum", visible: false},
{title: "InsertVon", field: "insertvon", visible: false},
{title: "UpdateAmUm", field: "format_updateamum", visible: false},
{title: "UpdateVon", field: "updatevon", visible: false},
{
title: 'Aktionen', field: 'actions',
minWidth: 150, // Ensures Action-buttons will be always fully displayed
formatter: (cell, formatterParams, onRendered) => {
//let disableButton = false;
//const rowData = this.row.getData();
let container = document.createElement('div');
container.className = "d-flex gap-2";
let button = document.createElement('button');
if (this.dataMeldestichtag && this.dataMeldestichtag > cell.getData().datum && !this.hasPermissionToSkipStatusCheck)
button.className = 'btn btn-outline-secondary btn-action disabled';
else
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-forward"></i>';
button.title = 'Status vorrücken';
button.addEventListener(
'click',
() =>
this.actionAdvanceStatus(cell.getData().status_kurzbz, cell.getData().studiensemester_kurzbz, cell.getData().ausbildungssemester)
);
container.append(button);
button = document.createElement('button');
if (this.dataMeldestichtag && this.dataMeldestichtag > cell.getData().datum && !this.hasPermissionToSkipStatusCheck)
button.className = 'btn btn-outline-secondary btn-action disabled';
else
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-check"></i>';
button.title = 'Status bestätigen';
button.addEventListener('click', () =>
this.actionConfirmStatus(cell.getData().status_kurzbz, cell.getData().studiensemester_kurzbz, cell.getData().ausbildungssemester)
);
container.append(button);
button = document.createElement('button');
if (this.dataMeldestichtag && this.dataMeldestichtag > cell.getData().datum && !this.hasPermissionToSkipStatusCheck)
button.className = 'btn btn-outline-secondary btn-action disabled';
else
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-edit"></i>';
button.title = 'Status bearbeiten';
button.addEventListener('click', (event) =>
this.actionEditStatus(cell.getData().status_kurzbz, cell.getData().studiensemester_kurzbz, cell.getData().ausbildungssemester)
);
container.append(button);
button = document.createElement('button');
if (this.dataMeldestichtag && this.dataMeldestichtag > cell.getData().datum && !this.hasPermissionToSkipStatusCheck)
button.className = 'btn btn-outline-secondary btn-action disabled';
else
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-xmark"></i>';
button.title = 'Status löschen';
button.addEventListener('click', () =>
this.actionDeleteStatus(cell.getData().status_kurzbz, cell.getData().studiensemester_kurzbz, cell.getData().ausbildungssemester)
);
container.append(button);
return container;
},
frozen: true
},
],
rowFormatter: (row) => {
const rowData = row.getData();
if (this.dataMeldestichtag && this.dataMeldestichtag > rowData.datum)
{
row.getElement().classList.add('disabled');
}
},
layout: 'fitDataFill',
layoutColumnsOnNewData: false,
height: 'auto',
selectable: false,
},
tabulatorEvents: [
{
event: 'tableBuilt',
handler: async () => {
await this.$p.loadCategory(['lehre','global','person']);
let cm = this.$refs.table.tabulator.columnManager;
/* cm.getColumnByField('lehrverband').component.updateDefinition({
title: this.$p.t('lehre', 'lehrverband')
});*/
cm.getColumnByField('format_bestaetigtam').component.updateDefinition({
title: this.$p.t('lehre', 'bestaetigt_am')
});
cm.getColumnByField('format_bewerbung_abgeschicktamum').component.updateDefinition({
title: this.$p.t('lehre', 'bewerbung_abgeschickt_am')
});
cm.getColumnByField('bezeichnung').component.updateDefinition({
title: this.$p.t('lehre', 'studienplan')
});
cm.getColumnByField('actions').component.updateDefinition({
title: this.$p.t('global', 'aktionen')
});
cm.getColumnByField('format_datum').component.updateDefinition({
title: this.$p.t('global', 'datum')
});
cm.getColumnByField('anmerkung').component.updateDefinition({
title: this.$p.t('global', 'anmerkung')
});
cm.getColumnByField('bestaetigtvon').component.updateDefinition({
title: this.$p.t('lehre', 'bestaetigt_von')
});
cm.getColumnByField('format_insertamum').component.updateDefinition({
title: this.$p.t('lehre', 'insert_am')
});
cm.getColumnByField('insertvon').component.updateDefinition({
title: this.$p.t('lehre', 'insert_von')
});
}
}
],
statusData: {},
listStudiensemester: [],
maxSem: Array.from({ length: 11 }, (_, index) => index),
listStudienplaene: [],
aufnahmestufen: {'': '-- keine Auswahl --', 1: 1, 2: 2, 3: 3},
listStatusgruende: [],
statusId: {},
gruendeLength: {},
dataMeldestichtag: null,
stichtag: {},
isLastStatus: {},
hasPermissionThisStg: {}
}
},
computed: {
gruende() {
return this.listStatusgruende.filter(grund => grund.status_kurzbz == this.statusData.status_kurzbz);
},
arrayStg(){
let stgInteger = this.hasAssistenzPermissionForStgs.map(item => {
return parseInt(item); // Wandelt jeden String in eine ganze Zahl um
});
return stgInteger;
},
hasPermissionCurrentStg(){
return this.arrayStg.includes(this.studiengang_kz);
}
},
watch: {
data: {
handler(n) {
const start = this.status_kurzbz;
},
deep: true
},
prestudent_id(){
this.$refs.table.tabulator.setData('api/frontend/v1/stv/Status/getHistoryPrestudent/' + this.prestudent_id);
}
},
methods: {
actionNewStatus() {
this.statusData.status_kurzbz = 'Interessent';
this.statusData.studiensemester_kurzbz = this.defaultSemester;
this.statusData.ausbildungssemester = 1;
this.statusData.datum = this.getDefaultDate();
this.statusData.bestaetigtam = this.getDefaultDate();
this.$refs.newStatusModal.show();
},
actionEditStatus(status, stdsem, ausbildungssemester){
this.statusId = {
'prestudent_id': this.prestudent_id,
'status_kurzbz': status,
'studiensemester_kurzbz': stdsem,
'ausbildungssemester': ausbildungssemester
};
this.loadStatus(this.statusId).then(() => {
if(this.statusData)
this.$refs.editStatusModal.show();
});
},
actionDeleteStatus(status, stdsem, ausbildungssemester){
this.statusId = {
'prestudent_id': this.prestudent_id,
'status_kurzbz': status,
'studiensemester_kurzbz': stdsem,
'ausbildungssemester': ausbildungssemester
};
this.checkIfLastStatus();
this.loadStatus(this.statusId).then(() => {
if(this.statusData)
this.$refs.deleteStatusModal.show();
});
},
actionAdvanceStatus(status, stdsem, ausbildungssemester){
this.statusId = {
'prestudent_id': this.prestudent_id,
'status_kurzbz': status,
'studiensemester_kurzbz': stdsem,
'ausbildungssemester': ausbildungssemester
};
this.loadStatus(this.statusId).then(() => {
if(this.statusData)
this.advanceStatus(this.statusId);
});
},
actionConfirmStatus(status, stdsem, ausbildungssemester){
this.statusId = {
'prestudent_id': this.prestudent_id,
'status_kurzbz': status,
'studiensemester_kurzbz': stdsem,
'ausbildungssemester': ausbildungssemester
};
this.loadStatus(this.statusId).then(() => {
if(this.statusData)
this.confirmStatus(this.statusId);
});
},
addNewStatus(){
this.$fhcApi.post('api/frontend/v1/stv/status/addNewStatus/' + this.prestudent_id,
this.statusData
).then(response => {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave'));
this.hideModal('newStatusModal');
this.resetModal();
}).catch(this.$fhcAlert.handleSystemError)
.finally(() => {
window.scrollTo(0, 0);
this.reload();
});
},
advanceStatus(statusId){
return this.$fhcApi.post('api/frontend/v1/stv/status/advanceStatus/' +
this.statusId.prestudent_id + '/' +
this.statusId.status_kurzbz + '/' +
this.statusId.studiensemester_kurzbz + '/' +
this.statusId.ausbildungssemester)
.then(
result => {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successAdvance'));
})
.catch(this.$fhcAlert.handleSystemError)
.finally(() => {
window.scrollTo(0, 0);
this.reload();
});
},
confirmStatus(statusId){
return this.$fhcApi.post('api/frontend/v1/stv/status/confirmStatus/' +
this.statusId.prestudent_id + '/' +
this.statusId.status_kurzbz + '/' +
this.statusId.studiensemester_kurzbz + '/' +
this.statusId.ausbildungssemester)
.then(
result => {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successConfirm'));
})
.catch(this.$fhcAlert.handleSystemError)
.finally(() => {
/* window.scrollTo(0, 0);*/
this.reload();
});
},
deleteStatus(status_id){
return this.$fhcApi.post('api/frontend/v1/stv/status/deleteStatus/',
status_id)
.then(
result => {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete'));
this.hideModal('deleteStatusModal');
this.resetModal();
})
.catch(this.$fhcAlert.handleSystemError)
.finally(() => {
window.scrollTo(0, 0);
this.reload();
});
},
editStatus(){
return this.$fhcApi.post('api/frontend/v1/stv/status/updateStatus/' +
this.statusId.prestudent_id + '/' +
this.statusId.status_kurzbz + '/' +
this.statusId.studiensemester_kurzbz + '/' +
this.statusId.ausbildungssemester,
this.statusData)
.then(
result => {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave'));
this.hideModal('editStatusModal');
this.resetModal();
})
.catch(this.$fhcAlert.handleSystemError)
.finally(() => {
window.scrollTo(0, 0);
this.reload();
});
},
checkIfLastStatus(){
return this.$fhcApi
.get('api/frontend/v1/stv/status/isLastStatus/' + this.prestudent_id)
.then(
result => {
if(result.data){
this.isLastStatus = result.data;
} else {
this.isLastStatus = {};
}
return result;
})
.catch(this.$fhcAlert.handleSystemError);
},
loadStatus(status_id){
return this.$fhcApi.post('api/frontend/v1/stv/status/loadStatus/',
status_id)
.then(result => {
this.statusData = result.data;
return result;
})
.catch(this.$fhcAlert.handleSystemError);
},
reload(){
this.$refs.table.reloadTable();
},
hideModal(modalRef){
this.$refs[modalRef].hide();
},
resetModal(){
this.statusData = {};
this.statusId = {};
},
getDefaultDate() {
const today = new Date();
return today;
}
},
created(){
this.$fhcApi
.get('api/frontend/v1/stv/prestudent/getStudiensemester')
.then(result => result.data)
.then(result => {
this.listStudiensemester = result;
})
.catch(this.$fhcAlert.handleSystemError);
this.$fhcApi
.get('api/frontend/v1/stv/prestudent/getStudienplaene/' + this.prestudent_id)
.then(result => result.data)
.then(result => {
this.listStudienplaene = result;
})
.catch(this.$fhcAlert.handleSystemError);
this.$fhcApi
.get('api/frontend/v1/stv/status/getStatusgruende/')
.then(result => result.data)
.then(result => {
this.listStatusgruende = result;
})
.catch(this.$fhcAlert.handleSystemError);
this.$fhcApi
.get('api/frontend/v1/stv/status/getLastBismeldestichtag/')
.then(result => result.data)
.then(result => {
this.dataMeldestichtag = result.retval[0].meldestichtag;
})
.catch(this.$fhcAlert.handleSystemError);
},
mounted(){
},
template: `
<div class="stv-list h-100 pt-3">
<!--Modal: Add New Status-->
<BsModal ref="newStatusModal">
<template #title>{{$p.t('lehre', 'status_new')}}</template>
<form-form class="row g-3" ref="statusData">
<div class="row mb-3">
<label for="status_kurzbz" class="form-label col-sm-4">{{$p.t('lehre', 'status_rolle')}}</label>
<div class="col-sm-6">
<!--<form-input type="text" :readonly="readonly" class="form-control" id="status_kurzbz" v-model="statusData['status_kurzbz']">-->
<form-input
required
v-model="statusData['status_kurzbz']"
name="status_kurzbz"
type="select"
>
<option value="Interessent">InteressentIn</option>
<option value="Bewerber">BewerberIn</option>
<option value="Aufgenommener">Aufgenommene/r</option>
<option value="Student">StudentIn</option>
<option value="Unterbrecher">UnterbrecherIn</option>
<option value="Diplomand">DiplomandIn</option>
<option value="Incoming">Incoming</option>
<option value="Absolvent">AbsolventIn</option>
<option value="Abbrecher">AbbrecherIn</option>
</form-input>
</div>
</div>
<div class="row mb-3">
<label for="studiensemester_kurzbz" class="form-label col-sm-4">{{$p.t('lehre', 'studiensemester')}}</label>
<div class="col-sm-6">
<form-input
:readonly="readonly"
type="select"
name="studiensemester_kurzbz"
v-model="statusData['studiensemester_kurzbz']"
>
<option v-for="sem in listStudiensemester" :key="sem.studiensemester_kurzbz" :value="sem.studiensemester_kurzbz" :selected="sem.studiensemester_kurzbz === defaultSemester">{{sem.studiensemester_kurzbz}}</option>
</form-input>
</div>
</div>
<!-- TODO(manu) if(defined('VORRUECKUNG_STATUS_MAX_SEMESTER') && VORRUECKUNG_STATUS_MAX_SEMESTER==false) 100 Semester-->
<div class="row mb-3">
<label for="ausbildungssemester" class="form-label col-sm-4">{{$p.t('lehre', 'ausbildungssemester')}}</label>
<div class="col-sm-6">
<form-input
type="select"
:readonly="readonly"
name="ausbildungssemester"
v-model="statusData.ausbildungssemester"
>
<option v-for="number in maxSem" :key="number" :value="number">{{ number }}</option>
</form-input>
</div>
</div>
<div class="row mb-3">
<label for="datum" class="form-label col-sm-4">{{$p.t('global', 'datum')}}</label>
<div class="col-sm-6">
<form-input
type="DatePicker"
:readonly="readonly"
name="datum"
v-model="statusData.datum"
auto-apply
:enable-time-picker="false"
format="dd.MM.yyyy"
preview-format="dd.MM.yyyy"
:teleport="true"
></form-input>
</div>
</div>
<div class="row mb-3">
<label for="bestaetigtam" class="form-label col-sm-4">{{$p.t('lehre', 'bestaetigt_am')}}</label>
<div class="col-sm-6">
<form-input
type="DatePicker"
:readonly="readonly"
name="datum"
v-model="statusData.bestaetigtam"
auto-apply
:enable-time-picker="false"
format="dd.MM.yyyy"
preview-format="dd.MM.yyyy"
:teleport="true"
></form-input>
</div>
</div>
<div class="row mb-3">
<label for="bewerbung_abgeschicktamum" class="form-label col-sm-4">{{$p.t('lehre', 'bewerbung_abgeschickt_am')}}</label>
<div class="col-sm-6">
<form-input
type="DatePicker"
:readonly="readonly"
name="datum"
v-model="statusData['bewerbung_abgeschicktamum']"
auto-apply
:enable-time-picker="false"
format="dd.MM.yyyy"
preview-format="dd.MM.yyyy"
:teleport="true"
></form-input>
</div>
</div>
<div class="row mb-3">
<label for="bezeichnung" class="form-label col-sm-4">{{$p.t('lehre', 'studienplan')}}</label>
<div class="col-sm-6">
<form-input
:readonly="readonly"
type="select"
name="studienplan"
v-model="statusData['studienplan_id']"
>
<option v-for="sp in listStudienplaene" :key="sp.studienplan_id" :value="sp.studienplan_id">{{sp.bezeichnung}}</option>
</form-input>
</div>
</div>
<div class="row mb-3">
<label for="anmerkung" class="form-label col-sm-4">{{$p.t('global', 'anmerkung')}}</label>
<div class="col-sm-6">
<form-input
type="text"
name="anmerkung"
v-model="statusData['anmerkung']"
>
</form-input>
</div>
</div>
<div class="row mb-3">
<label for="aufnahmestufe" class="form-label col-sm-4">{{$p.t('lehre', 'aufnahmestufe')}}</label>
<div class="col-sm-6">
<form-input
type="select"
:readonly="readonly"
name="aufnahmestufe"
v-model="statusData['rt_stufe']"
>
<option v-for="entry in aufnahmestufen" :key="entry" :value="entry">{{entry}}</option>
</form-input>
</div>
</div>
<div v-if="gruende.length > 0" class="row mb-3">
<label for="grund" class="form-label col-sm-4">{{$p.t('studierendenantrag', 'antrag_grund')}}</label>
<div class="col-sm-6">
<form-input
type="select"
:readonly="readonly"
name="statusgrund"
v-model="statusData['statusgrund_id']"
>
<option v-for="grund in gruende" :key="grund.statusgrund_id" :value="grund.statusgrund_id">{{grund.beschreibung[0]}}</option>
</form-input>
</div>
</div>
</form-form>
<template #footer>
<button type="button" class="btn btn-primary" @click="addNewStatus()">OK</button>
</template>
</BsModal>
<!--Modal: Edit Status-->
<BsModal ref="editStatusModal">
<template #title>{{$p.t('lehre', 'status_edit')}}</template>
<form-form class="row g-3" ref="statusData">
<div v-if="statusData.datum < dataMeldestichtag">
<b>{{$p.t('bismeldestichtag', 'meldestichtag_erreicht')}}</b>
</div>
<input type="hidden" id="statusId" name="statusId" value="statusData.statusId">
<div class="row mb-3">
<label for="status_kurzbz" class="form-label col-sm-4">{{$p.t('lehre', 'status_rolle')}}</label>
<div class="col-sm-6">
<!-- <form-input type="text" :readonly="readonly" class="form-control" id="status_kurzbz" v-model="statusData['status_kurzbz']">-->
<form-input
required
v-model="statusData['status_kurzbz']"
name="status_kurzbz"
type="select"
disabled
>
<option value="Interessent">InteressentIn</option>
<option value="Bewerber">BewerberIn</option>
<option value="Aufgenommener">Aufgenommene/r</option>
<option value="Student">StudentIn</option>
<option value="Unterbrecher">UnterbrecherIn</option>
<option value="Diplomand">DiplomandIn</option>
<option value="Incoming">Incoming</option>
<option value="Absolvent">AbsolventIn</option>
<option value="Abbrecher">AbbrecherIn</option>
</form-input>
</div>
</div>
<div class="row mb-3">
<label for="studiensemester_kurzbz" class="form-label col-sm-4">{{$p.t('lehre', 'studiensemester')}}</label>
<div class="col-sm-6">
<form-input
:readonly="readonly"
type="select"
name="studiensemester_kurzbz"
v-model="statusData['studiensemester_kurzbz']"
>
<option v-for="sem in listStudiensemester" :key="sem.studiensemester_kurzbz" :value="sem.studiensemester_kurzbz">{{sem.studiensemester_kurzbz}}</option>
</form-input>
</div>
</div>
<!-- TODO(manu) if(defined('VORRUECKUNG_STATUS_MAX_SEMESTER') && VORRUECKUNG_STATUS_MAX_SEMESTER==false)-->
<div class="row mb-3">
<label for="ausbildungssemester" class="form-label col-sm-4">{{$p.t('lehre', 'ausbildungssemester')}}</label>
<div class="col-sm-6">
<form-input
type="select"
:readonly="readonly"
name="ausbildungssemester"
v-model="statusData['ausbildungssemester']"
>
<option v-for="number in maxSem" :key="number" :value="number">{{ number }}</option>
</form-input>
</div>
</div>
<div class="row mb-3">
<label for="datum" class="form-label col-sm-4">{{$p.t('global', 'datum')}}</label>
<div class="col-sm-6">
<form-input
type="DatePicker"
:readonly="readonly"
name="datum"
v-model="statusData['datum']"
auto-apply
:enable-time-picker="false"
format="dd.MM.yyyy"
preview-format="dd.MM.yyyy"
:teleport="true"
></form-input>
</div>
</div>
<div class="row mb-3">
<label for="bestaetigtam" class="form-label col-sm-4">{{$p.t('lehre', 'bestaetigt_am')}}</label>
<div class="col-sm-6">
<form-input
type="DatePicker"
:readonly="readonly"
name="datum"
v-model="statusData['bestaetigtam']"
auto-apply
:enable-time-picker="false"
format="dd.MM.yyyy"
preview-format="dd.MM.yyyy"
:teleport="true"
></form-input>
</div>
</div>
<div class="row mb-3">
<label for="bewerbung_abgeschicktamum" class="form-label col-sm-4">{{$p.t('lehre', 'bewerbung_abgeschickt_am')}}</label>
<div class="col-sm-6">
<form-input
type="DatePicker"
:readonly="readonly"
name="datum"
v-model="statusData['bewerbung_abgeschicktamum']"
auto-apply
:enable-time-picker="false"
format="dd.MM.yyyy"
preview-format="dd.MM.yyyy"
:teleport="true"
></form-input>
</div>
</div>
<div class="row mb-3">
<label for="bezeichnung" class="form-label col-sm-4">{{$p.t('lehre', 'studienplan')}}</label>
<div class="col-sm-6">
<form-input
:readonly="readonly"
type="select"
name="studienplan"
v-model="statusData['studienplan_id']"
>
<option v-for="sp in listStudienplaene" :key="sp.studienplan_id" :value="sp.studienplan_id">{{sp.bezeichnung}}</option>
</form-input>
</div>
</div>
<div class="row mb-3">
<label for="anmerkung" class="form-label col-sm-4">{{$p.t('global', 'anmerkung')}}</label>
<div class="col-sm-6">
<form-input
type="text"
name="anmerkung"
v-model="statusData['anmerkung']"
>
</form-input>
</div>
</div>
<div class="row mb-3">
<label for="aufnahmestufe" class="form-label col-sm-4">{{$p.t('lehre', 'aufnahmestufe')}}</label>
<div class="col-sm-6">
<form-input
type="select"
:readonly="readonly"
name="aufnahmestufe"
v-model="statusData['rt_stufe']"
>
<option v-for="entry in aufnahmestufen" :key="entry" :value="entry">{{entry}}</option>
</form-input>
</div>
</div>
<div v-if="gruende.length > 0" class="row mb-3">
<label for="grund" class="form-label col-sm-4">{{$p.t('studierendenantrag', 'antrag_grund')}}</label>
<div class="col-sm-6">
<form-input
type="select"
:readonly="readonly"
name="statusgrund"
v-model="statusData['statusgrund_id']"
>
<option v-for="grund in gruende" :key="grund.statusgrund_id" :value="grund.statusgrund_id">{{grund.beschreibung[0]}}</option>
</form-input>
</div>
</div>
</form-form>
<template #footer>
<button type="button" class="btn btn-primary" @click="editStatus()">OK</button>
</template>
</BsModal>
<!--Modal: Delete Status-->
<BsModal ref="deleteStatusModal">
<template #title>{{$p.t('lehre', 'status_edit')}}</template>
<template #default>
<div v-if="isLastStatus == 1">
<p>{{$p.t('lehre', 'last_status_confirm_delete')}}</p>
</div>
<div v-else>
<p>{{$p.t('lehre', 'status_confirm_delete')}}</p>
</div>
</template>
<template #footer>
<button ref="Close" type="button" class="btn btn-primary" @click="deleteStatus(statusId)">OK</button>
</template>
</BsModal>
<core-filter-cmpt
ref="table"
:tabulator-options="tabulatorOptions"
:tabulator-events="tabulatorEvents"
table-only
:side-menu="false"
reload
new-btn-show
new-btn-label="Status"
@click:new="actionNewStatus"
>
<template #actions="{selected}">
<button
class="btn btn-outline-primary"
@click="actionChangeStatus(selected)"
> Status Ändern
</button>
<!-- <div class="input-group w-auto">
<form-input
type="DatePicker"
v-model="counterdate"
input-group
:enable-time-picker="false"
auto-apply
@cleared="counterdate = new Date()"
>
</form-input>
<button
class="btn btn-outline-secondary"
@click="actionCounter(selected)"
:disabled="!selected.length"
>
Gegenbuchen
</button>
</div>
<button
v-if="config.showZahlungsbestaetigung"
class="btn btn-outline-secondary"
@click="downloadPdf(selected)"
:disabled="!selected.length"
>
<i class="fa fa-download"></i> Zahlungsbestaetigung
</button>-->
</template>
</core-filter-cmpt>
</div>`
};
@@ -1,25 +0,0 @@
import TblStatus from "./Prestudent/Status.js";
import TblMultiStatus from "./Prestudent/MultiStatus.js";
export default {
components: {
TblStatus,
TblMultiStatus
},
props: {
modelValue: Object,
},
template: `
<div class="stv-details-details h-100 pb-3">
<TblMultiStatus :modelValue="modelValue"></TblMultiStatus>
</div>
<div class="stv-details-details h-100 pb-3">
<div class="col-12 pb-3">
<legend>Status</legend>
<TblStatus :prestudent_id="modelValue.prestudent_id" :studiengang_kz="modelValue.studiengang_kz"></TblStatus>
</div>
</div>
`
}
@@ -2,11 +2,15 @@ import {CoreFilterCmpt} from "../../filter/Filter.js";
import {CoreRESTClient} from '../../../RESTClient.js';
import ListNew from './List/New.js';
export default {
components: {
CoreFilterCmpt,
ListNew
},
inject: [
'lists'
],
props: {
selected: Array,
studiengangKz: Number,
@@ -79,7 +83,9 @@ export default {
}
],
focusObj: null, // TODO(chris): this should be in the filter component
lastSelected: null
lastSelected: null,
filterKontoCount0: undefined,
filterKontoMissingCounter: undefined
}
},
methods: {
@@ -113,17 +119,29 @@ export default {
},
updateUrl(url, first) {
this.lastSelected = first ? undefined : this.selected;
if (url)
url = CoreRESTClient._generateRouterURI(url);
const params = {}, filter = {};
if (this.filterKontoCount0)
filter.konto_count_0 = this.filterKontoCount0;
if (this.filterKontoMissingCounter)
filter.konto_missing_counter = this.filterKontoMissingCounter;
if (filter.konto_count_0 || filter.konto_missing_counter)
params.filter = filter;
if (!this.$refs.table.tableBuilt) {
if (!this.$refs.table.tabulator) {
this.tabulatorOptions.ajaxURL = url;
this.tabulatorOptions.ajaxParams = params;
} else
this.$refs.table.tabulator.on("tableBuilt", () => {
this.$refs.table.tabulator.setData(url);
this.$refs.table.tabulator.setData(url, params);
});
} else
this.$refs.table.tabulator.setData(url);
this.$refs.table.tabulator.setData(url, params);
},
onKeydown(e) { // TODO(chris): this should be in the filter component
if (!this.focusObj)
@@ -182,7 +200,7 @@ export default {
// TODO(chris): filter component column chooser has no accessibilty features
template: `
<div class="stv-list h-100 pt-3">
<div class="tablulator-container d-flex flex-column h-100" tabindex="0" @focusin="onFocus" @focusout="onBlur" @keydown="onKeydown">
<div class="tablulator-container d-flex flex-column h-100" :class="{'has-filter': filterKontoCount0 || filterKontoMissingCounter}" tabindex="0" @focusin="onFocus" @focusout="onBlur" @keydown="onKeydown">
<core-filter-cmpt
ref="table"
:tabulator-options="tabulatorOptions"
@@ -191,9 +209,38 @@ export default {
:side-menu="false"
reload
new-btn-show
new-btn-label="InteressentIn"
:new-btn-label="$p.t('stv/action_new')"
@click:new="actionNewPrestudent"
>
<template #filter>
<div class="card">
<div class="card-body">
<div class="input-group mb-3">
<label class="input-group-text col-4" for="stv-list-filter-konto-count-0">{{ $p.t('stv/konto_filter_count_0') }}</label>
<select class="form-select" id="stv-list-filter-konto-count-0" v-model="filterKontoCount0" @input="$nextTick(updateUrl)">
<option v-for="typ in lists.buchungstypen" :key="typ.buchungstyp_kurzbz" :value="typ.buchungstyp_kurzbz">
{{ typ.beschreibung }}
</option>
</select>
<button v-if="filterKontoCount0" class="btn btn-outline-secondary" @click="filterKontoCount0 = undefined; updateUrl()">
<i class="fa fa-times"></i>
</button>
</div>
<div class="input-group">
<label class="input-group-text col-4" for="stv-list-filter-konto-missing-counter">{{ $p.t('stv/konto_filter_missing_counter') }}</label>
<select class="form-select" id="stv-list-filter-konto-missing-counter" v-model="filterKontoMissingCounter" @input="$nextTick(updateUrl)">
<option value="alle">{{ $p.t('stv/konto_all_types') }}</option>
<option v-for="typ in lists.buchungstypen" :key="typ.buchungstyp_kurzbz" :value="typ.buchungstyp_kurzbz">
{{ typ.beschreibung }}
</option>
</select>
<button v-if="filterKontoMissingCounter" class="btn btn-outline-secondary" @click="filterKontoMissingCounter = undefined; updateUrl()">
<i class="fa fa-times"></i>
</button>
</div>
</div>
</div>
</template>
</core-filter-cmpt>
</div>
<list-new ref="new" :studiengang-kz="studiengangKz" :studiensemester-kurzbz="studiensemesterKurzbz"></list-new>
+17 -2
View File
@@ -17,10 +17,11 @@
import {CoreFilterAPIs} from './API.js';
import {CoreRESTClient} from '../../RESTClient.js';
import {CoreFetchCmpt} from '../../components/Fetch.js';
import {CoreFetchCmpt} from '../Fetch.js';
import FilterConfig from './Filter/Config.js';
import FilterColumns from './Filter/Columns.js';
import TableDownload from './Table/Download.js';
import collapseAutoClose from '../../directives/collapseAutoClose.js';
//
const FILTER_COMPONENT_NEW_FILTER = 'Filter Component New Filter';
@@ -38,6 +39,9 @@ export const CoreFilterCmpt = {
FilterColumns,
TableDownload
},
directives: {
collapseAutoClose
},
emits: [
'nwNewEntry',
'click:new'
@@ -543,7 +547,7 @@ export const CoreFilterCmpt = {
</div>
<div class="d-flex gap-1 align-items-baseline flex-grow-1 justify-content-end">
<span v-if="!tableOnly">[ {{ filterName }} ]</span>
<a v-if="!tableOnly" href="#" class="btn btn-link px-0 text-dark" data-bs-toggle="collapse" :data-bs-target="'#collapseFilters' + idExtra">
<a v-if="!tableOnly || $slots.filter" href="#" class="btn btn-link px-0 text-dark" data-bs-toggle="collapse" :data-bs-target="'#collapseFilters' + idExtra">
<span class="fa-solid fa-xl fa-filter"></span>
</a>
<a href="#" class="btn btn-link px-0 text-dark" data-bs-toggle="collapse" :data-bs-target="'#collapseColumns' + idExtra">
@@ -562,6 +566,7 @@ export const CoreFilterCmpt = {
:names="fieldNames"
@hide="tabulator.hideColumn($event)"
@show="tabulator.showColumn($event)"
v-collapse-auto-close
></filter-columns>
<filter-config
@@ -575,7 +580,17 @@ export const CoreFilterCmpt = {
@switch-filter="switchFilter"
@apply-filter-config="applyFilterConfig"
@save-custom-filter="handlerSaveCustomFilter"
v-collapse-auto-close
></filter-config>
<div
v-else-if="$slots.filter"
:id="'collapseFilters' + idExtra"
class="card-body collapse"
:data-bs-parent="'#filterCollapsables' + idExtra"
v-collapse-auto-close
>
<slot name="filter"></slot>
</div>
</div>
<!-- Tabulator -->
+29
View File
@@ -0,0 +1,29 @@
const elementDataMap = new WeakMap();
export default {
mounted(el, binding) {
let open = false;
elementDataMap.set(el, evt => {
if (!open)
return;
if (el.contains(evt.target))
return;
const collapse = bootstrap.Collapse.getInstance(el)
if (collapse)
collapse.hide();
});
el.addEventListener('shown.bs.collapse', () => {
open = true;
});
el.addEventListener('hide.bs.collapse', () => {
open = false;
});
document.addEventListener('click', elementDataMap.get(el), true);
},
beforeUnmount(el, binding) {
document.removeEventListener('click', elementDataMap.get(el));
delete el.collapsibleAutoHideFunc;
}
}
File diff suppressed because it is too large Load Diff