mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-06-23 15:09:37 +00:00
Merge branch 'studvw_2025-11_rc2' into demo-cis40
This commit is contained in:
@@ -61,7 +61,11 @@ $config['tabs'] =
|
||||
'notes' => [
|
||||
//if true, the count of Messages will be shown in the header of the Tab Messages
|
||||
'showCountNotes' => true
|
||||
]
|
||||
],
|
||||
'combinePeople' => [
|
||||
//multitab should only be shown with this length of selection
|
||||
'validCountMulti' => 2,
|
||||
],
|
||||
];
|
||||
|
||||
// List of fields to show when ZGV_DOKTOR_ANZEIGEN is defined
|
||||
@@ -117,5 +121,6 @@ $config['students_tab_order'] = [
|
||||
'status',
|
||||
'groups',
|
||||
'finalexam',
|
||||
'combinePeople',
|
||||
'archive',
|
||||
];
|
||||
|
||||
@@ -33,6 +33,8 @@ class Config extends FHCAPI_Controller
|
||||
{
|
||||
// TODO(chris): permissions
|
||||
parent::__construct([
|
||||
'get' => ['admin:r', 'assistenz:r'],
|
||||
'set' => ['admin:r', 'assistenz:r'],
|
||||
'filter' => ['admin:r', 'assistenz:r'],
|
||||
'student' => ['admin:r', 'assistenz:r'],
|
||||
'students' => ['admin:r', 'assistenz:r']
|
||||
@@ -55,6 +57,95 @@ class Config extends FHCAPI_Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* get App config
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$this->load->model('system/Variable_model', 'VariableModel');
|
||||
$this->load->config('stv');
|
||||
|
||||
$config = [];
|
||||
|
||||
#number_displayed_past_studiensemester
|
||||
$result = $this->VariableModel->getVariables(getAuthUID(), ['number_displayed_past_studiensemester']);
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$number_displayed_past_studiensemester_default = $this->config->item('number_displayed_past_studiensemester_default');
|
||||
|
||||
$config['number_displayed_past_studiensemester'] = [
|
||||
"type" => "number",
|
||||
"label" => $this->p->t('stv', 'settings_no_displayed_past_sem'),
|
||||
"value" => $data['number_displayed_past_studiensemester']
|
||||
?? $number_displayed_past_studiensemester_default
|
||||
];
|
||||
|
||||
#font_size
|
||||
$result = $this->VariableModel->getVariables(getAuthUID(), ['stv_font_size']);
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
$config['font_size'] = [
|
||||
"type" => "select",
|
||||
"label" => $this->p->t('stv', 'settings_fontsize'),
|
||||
"value" => $data['stv_font_size'] ?? "fs_normal",
|
||||
"options" => [
|
||||
"fs_xx-small" => $this->p->t('stv', 'settings_fontsize_xx-small'),
|
||||
"fs_x-small" => $this->p->t('stv', 'settings_fontsize_x-small'),
|
||||
"fs_small" => $this->p->t('stv', 'settings_fontsize_small'),
|
||||
"fs_normal" => $this->p->t('stv', 'settings_fontsize_normal'),
|
||||
"fs_big" => $this->p->t('stv', 'settings_fontsize_big'),
|
||||
"fs_huge" => $this->p->t('stv', 'settings_fontsize_huge')
|
||||
]
|
||||
];
|
||||
|
||||
#others
|
||||
Events::trigger('stv_config_get', function & () use (&$config) {
|
||||
return $config;
|
||||
});
|
||||
|
||||
$this->terminateWithSuccess($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* set App config
|
||||
*/
|
||||
public function set()
|
||||
{
|
||||
$this->load->model('system/Variable_model', 'VariableModel');
|
||||
$this->load->library('form_validation');
|
||||
|
||||
$this->form_validation->set_rules(
|
||||
'number_displayed_past_studiensemester',
|
||||
$this->p->t('stv', 'settings_no_displayed_past_sem'),
|
||||
'required|integer'
|
||||
);
|
||||
$this->form_validation->set_rules(
|
||||
'font_size',
|
||||
$this->p->t('stv', 'settings_fontsize'),
|
||||
'required|in_list[fs_xx-small,fs_x-small,fs_small,fs_normal,fs_big,fs_huge]'
|
||||
);
|
||||
|
||||
Events::trigger('stv_config_validation', $this->form_validation);
|
||||
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
|
||||
$this->VariableModel->setVariable(
|
||||
getAuthUID(),
|
||||
'number_displayed_past_studiensemester',
|
||||
$this->input->post('number_displayed_past_studiensemester')
|
||||
);
|
||||
$this->VariableModel->setVariable(
|
||||
getAuthUID(),
|
||||
'stv_font_size',
|
||||
$this->input->post('font_size')
|
||||
);
|
||||
|
||||
Events::trigger('stv_config_set', $this->input);
|
||||
|
||||
$this->terminateWithSuccess();
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the config for the student filters
|
||||
*
|
||||
* @return void
|
||||
@@ -407,6 +498,15 @@ class Config extends FHCAPI_Controller
|
||||
]
|
||||
];
|
||||
|
||||
if($this->permissionlib->isBerechtigt('basis/person'))
|
||||
{
|
||||
$result['combinePeople'] = [
|
||||
'title' => $this->p->t('stv', 'tab_combine_people'),
|
||||
'component' => './Stv/Studentenverwaltung/Details/CombinePeople.js',
|
||||
'config' => $config['combinePeople']
|
||||
];
|
||||
}
|
||||
|
||||
$result['kontaktieren'] = [
|
||||
'title' => $this->p->t('stv', 'tab_kontaktieren'),
|
||||
'component' => absoluteJsImportUrl('public/js/components/Stv/Studentenverwaltung/Details/Kontaktieren.js'),
|
||||
|
||||
@@ -765,6 +765,86 @@ class Students extends FHCAPI_Controller
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $studiensemester_kurzbz
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function search($studiensemester_kurzbz)
|
||||
{
|
||||
$this->addMeta('ci_method', __FUNCTION__);
|
||||
$this->addMeta('ci_params', array(
|
||||
'studiensemester_kurzbz' => $studiensemester_kurzbz
|
||||
));
|
||||
|
||||
$this->load->library('SearchLib', [ 'config' => 'searchstv' ]);
|
||||
$this->load->library('form_validation');
|
||||
|
||||
$this->form_validation->set_rules('searchstr', 'searchstr', 'required');
|
||||
$this->form_validation->set_rules('types[]', 'types', 'required');
|
||||
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
$result = $this->searchlib->search($this->input->post('searchstr'), $this->input->post('types'));
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
|
||||
$this->load->model('crm/Prestudent_model', 'PrestudentModel');
|
||||
|
||||
$this->prepareQuery($studiensemester_kurzbz);
|
||||
|
||||
$this->PrestudentModel->addSelect("COALESCE(v.semester::text, CASE WHEN public.get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL) IN ('Aufgenommener', 'Bewerber', 'Wartender', 'interessent') THEN public.get_absem_prestudent(tbl_prestudent.prestudent_id, NULL)::text ELSE ''::text END) AS semester", false);
|
||||
$this->PrestudentModel->addSelect('v.verband');
|
||||
$this->PrestudentModel->addSelect('v.gruppe');
|
||||
|
||||
//add status per semester
|
||||
$this->PrestudentModel->addSelect(
|
||||
"(
|
||||
SELECT status_kurzbz
|
||||
FROM public.tbl_prestudentstatus pss
|
||||
WHERE pss.prestudent_id = public.tbl_prestudent.prestudent_id
|
||||
AND pss.studiensemester_kurzbz = " . $this->PrestudentModel->escape($studiensemester_kurzbz) . "
|
||||
ORDER BY GREATEST(pss.datum, '0001-01-01') DESC
|
||||
LIMIT 1
|
||||
) AS statusofsemester"
|
||||
);
|
||||
|
||||
$this->addSelectPrioRel();
|
||||
|
||||
$this->addFilter($studiensemester_kurzbz);
|
||||
|
||||
$prestudent_ids = [];
|
||||
$student_uids = [];
|
||||
$this->addMeta('data', $data);
|
||||
foreach ($data as $row) {
|
||||
$dataset = json_decode($row->data);
|
||||
if ($row->type == 'prestudent') {
|
||||
$prestudent_ids[] = $dataset->prestudent_id;
|
||||
} elseif ($row->type == 'student') {
|
||||
$student_uids[] = $dataset->uid;
|
||||
}
|
||||
}
|
||||
|
||||
if ($prestudent_ids && $student_uids) {
|
||||
$this->PrestudentModel->db->where_in('tbl_prestudent.prestudent_id', $prestudent_ids);
|
||||
$this->PrestudentModel->db->or_where_in('s.student_uid', $student_uids);
|
||||
} elseif ($prestudent_ids) {
|
||||
$this->PrestudentModel->db->where_in('tbl_prestudent.prestudent_id', $prestudent_ids);
|
||||
} elseif ($student_uids) {
|
||||
$this->PrestudentModel->db->where_in('s.student_uid', $student_uids);
|
||||
} else {
|
||||
$this->terminateWithSuccess([]);
|
||||
}
|
||||
|
||||
$result = $this->PrestudentModel->load();
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $studiensemester_kurzbz
|
||||
* @param string $type
|
||||
|
||||
@@ -165,7 +165,17 @@ class Verband extends FHCAPI_Controller
|
||||
|
||||
$this->StudiengangModel->addDistinct();
|
||||
$this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", semester) AS link", false);
|
||||
$this->StudiengangModel->addSelect("CONCAT(UPPER(CONCAT(typ, kurzbz)), '-', semester, (SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END FROM public.tbl_lehrverband WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester ORDER BY verband, gruppe LIMIT 1)) AS name", false);
|
||||
$this->StudiengangModel->addSelect("CONCAT(
|
||||
UPPER(CONCAT(typ, kurzbz)),
|
||||
'-',
|
||||
semester,
|
||||
(
|
||||
SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END
|
||||
FROM public.tbl_lehrverband
|
||||
WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester
|
||||
ORDER BY verband, gruppe LIMIT 1
|
||||
)
|
||||
) AS name", false);
|
||||
|
||||
$this->StudiengangModel->addSelect('semester');
|
||||
$this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false);
|
||||
@@ -173,6 +183,7 @@ class Verband extends FHCAPI_Controller
|
||||
$this->StudiengangModel->addOrder('semester');
|
||||
|
||||
if ($org_form !== null) {
|
||||
$this->StudiengangModel->addSelect("v.orgform_kurzbz");
|
||||
$this->StudiengangModel->db->group_start();
|
||||
$this->StudiengangModel->db->where('v.semester', 0);
|
||||
$this->StudiengangModel->db->or_where('v.orgform_kurzbz', $org_form);
|
||||
@@ -188,6 +199,7 @@ class Verband extends FHCAPI_Controller
|
||||
array_unshift($list, [
|
||||
'name' => 'PreStudent',
|
||||
'link' => $link . 'prestudent',
|
||||
'no_sem_reload' => true,
|
||||
'stg_kz' => (int)$studiengang_kz,
|
||||
'children' => $this->getStdSem($link . 'prestudent/', $studiengang_kz)
|
||||
]);
|
||||
@@ -216,7 +228,6 @@ class Verband extends FHCAPI_Controller
|
||||
$list = array_merge($list, $result);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
$this->terminateWithSuccess($list);
|
||||
}
|
||||
|
||||
@@ -53,6 +53,8 @@ $configArray = [
|
||||
active-addons="<?= defined('ACTIVE_ADDONS') ? ACTIVE_ADDONS : ''; ?>"
|
||||
stv-root="<?= site_url('Studentenverwaltung'); ?>"
|
||||
cis-root="<?= CIS_ROOT; ?>"
|
||||
avatar-url="<?= site_url('Cis/Pub/bild/person/' . getAuthPersonId()); ?>"
|
||||
logout-url="<?= site_url('Cis/Auth/logout'); ?>"
|
||||
:permissions="<?= htmlspecialchars(json_encode($permissions)); ?>"
|
||||
:config="<?= htmlspecialchars(json_encode($configArray)); ?>"
|
||||
>
|
||||
|
||||
@@ -11,6 +11,24 @@
|
||||
html {
|
||||
font-size: .875em;
|
||||
}
|
||||
html.fs_xx-small {
|
||||
font-size: .5em;
|
||||
}
|
||||
html.fs_x-small {
|
||||
font-size: .625em;
|
||||
}
|
||||
html.fs_small {
|
||||
font-size: .75em;
|
||||
}
|
||||
html.fs_normal {
|
||||
font-size: .875em;
|
||||
}
|
||||
html.fs_big {
|
||||
font-size: 1em;
|
||||
}
|
||||
html.fs_huge {
|
||||
font-size: 1.125em;
|
||||
}
|
||||
|
||||
#appMenu {
|
||||
width: 300px;
|
||||
@@ -43,6 +61,12 @@ html {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
#nav-user-btn img {
|
||||
object-fit: contain;
|
||||
height: 2.5rem;
|
||||
width: 2.5rem;
|
||||
}
|
||||
|
||||
.tabulator-row.disabled.tabulator-row-odd .tabulator-cell {
|
||||
color: var(--gray-400);
|
||||
}
|
||||
@@ -160,4 +184,4 @@ html {
|
||||
|
||||
.tiny-90 div.tox.tox-tinymce {
|
||||
height: 90% !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,15 @@
|
||||
padding: .5rem 1rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
.fhc-app-menu li a.disabled {
|
||||
--bs-link-opacity: .5;
|
||||
}
|
||||
.fhc-app-menu li a.active,
|
||||
.fhc-app-menu li a:hover {
|
||||
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
|
||||
background: var(--surface-hover);
|
||||
}
|
||||
.fhc-app-menu li a.disabled,
|
||||
.fhc-app-menu li a.active {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (C) 2025 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/>.
|
||||
*/
|
||||
|
||||
export default {
|
||||
get() {
|
||||
return {
|
||||
method: 'get',
|
||||
url: 'api/frontend/v1/stv/config/get'
|
||||
};
|
||||
},
|
||||
set(params) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: 'api/frontend/v1/stv/config/set',
|
||||
params
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -46,6 +46,14 @@ export default {
|
||||
url: url
|
||||
};
|
||||
},
|
||||
search(params, studiensemester_kurzbz) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: 'api/frontend/v1/stv/students/search/'
|
||||
+ encodeURIComponent(studiensemester_kurzbz),
|
||||
params
|
||||
};
|
||||
},
|
||||
verband(relative_path) {
|
||||
return {
|
||||
method: 'get',
|
||||
|
||||
@@ -148,6 +148,44 @@ const router = VueRouter.createRouter({
|
||||
next();
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'search',
|
||||
path: `/${ciPath}/studentenverwaltung/:studiensemester_kurzbz/search/:searchstr`,
|
||||
component: FhcStudentenverwaltung,
|
||||
props(route) {
|
||||
return {
|
||||
url_studiensemester_kurzbz: route.params.studiensemester_kurzbz,
|
||||
url_mode: 'search',
|
||||
url_prestudent_id: route.params.searchstr
|
||||
};
|
||||
},
|
||||
beforeEnter(to, from, next) {
|
||||
const isSemester = /^[WS]S\d{4}$/.test(to.params.studiensemester_kurzbz);
|
||||
if (!isSemester) {
|
||||
return next({name: 'index'});
|
||||
}
|
||||
next();
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'search_w_types',
|
||||
path: `/${ciPath}/studentenverwaltung/:studiensemester_kurzbz/search/:types/:searchstr`,
|
||||
component: FhcStudentenverwaltung,
|
||||
props(route) {
|
||||
return {
|
||||
url_studiensemester_kurzbz: route.params.studiensemester_kurzbz,
|
||||
url_mode: 'search',
|
||||
url_prestudent_id: route.params.type + '/' + route.params.searchstr
|
||||
};
|
||||
},
|
||||
beforeEnter(to, from, next) {
|
||||
const isSemester = /^[WS]S\d{4}$/.test(to.params.studiensemester_kurzbz);
|
||||
if (!isSemester) {
|
||||
return next({name: 'index'});
|
||||
}
|
||||
next();
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
redirect: {
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Copyright (C) 2025 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/>.
|
||||
*/
|
||||
|
||||
import BsModal from "./Bootstrap/Modal.js";
|
||||
import FhcForm from "./Form/Form.js";
|
||||
import FormInput from "./Form/Input.js";
|
||||
|
||||
|
||||
export default {
|
||||
name: 'AppConfig',
|
||||
components: {
|
||||
BsModal,
|
||||
FhcForm,
|
||||
FormInput
|
||||
},
|
||||
emits: [
|
||||
'update:modelValue'
|
||||
],
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
endpoints: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
setup: {},
|
||||
tempValues: {}
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
'$p.user_language.value'(n, o) {
|
||||
if (n !== o && o !== undefined && Object.keys(this.setup).length) {
|
||||
this.$api
|
||||
.call(this.endpoints.get())
|
||||
.then(res => {
|
||||
this.setup = {};
|
||||
Object.keys(res.data).forEach(key => {
|
||||
const binding = { ...res.data[key] };
|
||||
delete binding.value;
|
||||
delete binding.options;
|
||||
const options = res.data[key].options;
|
||||
this.setup[key] = {
|
||||
binding,
|
||||
options
|
||||
};
|
||||
});
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemErrors);
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.$refs.form
|
||||
.call(this.endpoints.set(this.tempValues))
|
||||
.then(() => {
|
||||
this.$emit('update:modelValue', { ...this.tempValues });
|
||||
this.$refs.modal.hide();
|
||||
this.$fhcAlert.alertSuccess(this.$p.t('ui/settings_saved'));
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemErrors);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$api
|
||||
.call(this.endpoints.get())
|
||||
.then(res => {
|
||||
Object.keys(res.data).forEach(key => {
|
||||
const binding = { ...res.data[key] };
|
||||
delete binding.value;
|
||||
delete binding.options;
|
||||
const options = res.data[key].options;
|
||||
this.tempValues[key] = res.data[key].value;
|
||||
this.setup[key] = {
|
||||
binding,
|
||||
options
|
||||
};
|
||||
});
|
||||
this.$emit('update:modelValue', { ...this.tempValues });
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemErrors);
|
||||
},
|
||||
template: /* html */`
|
||||
<fhc-form class="stv-config" ref="form" @submit.prevent="update">
|
||||
<bs-modal
|
||||
ref="modal"
|
||||
class="fade"
|
||||
id="configModal"
|
||||
dialog-class="modal-lg"
|
||||
@hidden-bs-modal="tempValues = { ...modelValue }"
|
||||
>
|
||||
<template #title>{{ $p.t('ui/settings') }}</template>
|
||||
<template #default>
|
||||
<div class="d-flex flex-column gap-5">
|
||||
<form-input
|
||||
v-for="(value, key) in setup"
|
||||
v-model="tempValues[key]"
|
||||
v-bind="value.binding"
|
||||
>
|
||||
<option
|
||||
v-for="(label, val) in value.options"
|
||||
:key="val"
|
||||
:value="val"
|
||||
>{{ label }}</option>
|
||||
</form-input>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<button class="btn btn-primary" type="submit">
|
||||
{{ $p.t('ui/speichern') }}
|
||||
</button>
|
||||
</template>
|
||||
</bs-modal>
|
||||
</fhc-form>`
|
||||
};
|
||||
@@ -64,5 +64,6 @@ export default {
|
||||
{{ menu.description }}
|
||||
</a>
|
||||
</li>
|
||||
<slot />
|
||||
</ul>`
|
||||
};
|
||||
|
||||
@@ -316,7 +316,7 @@ export default {
|
||||
template: /* html */`
|
||||
<div
|
||||
class="fhc-calendar-base-grid"
|
||||
style="display:grid;width:100%;height:100%"
|
||||
style="display:grid;width:100%;height:100%;overflow:auto"
|
||||
:style="'grid-template-' + axisRow + 's:auto' + (allDayEvents ? ' auto ' : ' ') + '1fr;grid-template-' + axisCol + 's:auto ' + styleGridCols"
|
||||
>
|
||||
<div
|
||||
|
||||
@@ -124,6 +124,10 @@ export default {
|
||||
? `${this.stg}/${this.semester}`
|
||||
: this.stg;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.selectedStudiengang = '';
|
||||
}
|
||||
this.filter = filter;
|
||||
},
|
||||
handleRowClicked(data)
|
||||
@@ -163,6 +167,7 @@ export default {
|
||||
const routeName = this.filter.emp ? 'byEmp' : 'byStg';
|
||||
const params = { stg };
|
||||
|
||||
params.semester = '';
|
||||
if (semester !== null)
|
||||
params.semester = semester;
|
||||
if (studiensemester_kurzbz)
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
*/
|
||||
|
||||
import CoreSearchbar from "../searchbar/searchbar.js";
|
||||
import NavLanguage from "../navigation/Language.js";
|
||||
import VerticalSplit from "../verticalsplit/verticalsplit.js";
|
||||
import AppMenu from "../AppMenu.js";
|
||||
import AppConfig from "../AppConfig.js";
|
||||
import StvVerband from "./Studentenverwaltung/Verband.js";
|
||||
import StvList from "./Studentenverwaltung/List.js";
|
||||
import StvDetails from "./Studentenverwaltung/Details.js";
|
||||
@@ -26,14 +28,17 @@ import StvStudiensemester from "./Studentenverwaltung/Studiensemester.js";
|
||||
import ApiSearchbar from "../../api/factory/searchbar.js";
|
||||
import ApiStv from "../../api/factory/stv.js";
|
||||
import ApiStvVerband from '../../api/factory/stv/verband.js';
|
||||
import ApiStvConfig from '../../api/factory/stv/config.js';
|
||||
|
||||
|
||||
export default {
|
||||
name: 'Studentenverwaltung',
|
||||
components: {
|
||||
CoreSearchbar,
|
||||
NavLanguage,
|
||||
VerticalSplit,
|
||||
AppMenu,
|
||||
AppConfig,
|
||||
StvVerband,
|
||||
StvList,
|
||||
StvDetails,
|
||||
@@ -45,6 +50,8 @@ export default {
|
||||
permissions: Object,
|
||||
stvRoot: String,
|
||||
cisRoot: String,
|
||||
avatarUrl: String,
|
||||
logoutUrl: String,
|
||||
activeAddons: String, // semicolon separated list of active addons
|
||||
url_studiensemester_kurzbz: String,
|
||||
url_mode: String,
|
||||
@@ -76,15 +83,19 @@ export default {
|
||||
},
|
||||
configShowAufnahmegruppen: this.config.showAufnahmegruppen,
|
||||
configAllowUebernahmePunkte: this.config.allowUebernahmePunkte,
|
||||
configUseReihungstestPunkte: this.config.useReihungstestPunkte
|
||||
configUseReihungstestPunkte: this.config.useReihungstestPunkte,
|
||||
appConfig: Vue.computed(() => this.appconfig)
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
appconfig: {},
|
||||
configEndpoints: ApiStvConfig,
|
||||
selected: [],
|
||||
searchbaroptions: {
|
||||
origin: 'stv',
|
||||
calcheightonly: true,
|
||||
nolivesearch: true,
|
||||
types: {
|
||||
student: Vue.computed(() => this.$p.t('search/type_student')),
|
||||
prestudent: Vue.computed(() => this.$p.t('search/type_prestudent'))
|
||||
@@ -123,6 +134,8 @@ export default {
|
||||
studiengangKz: undefined,
|
||||
studiengangKuerzel: '',
|
||||
studiensemesterKurzbz: this.defaultSemester,
|
||||
selected_semester: undefined,
|
||||
selected_orgform: undefined,
|
||||
lists: {
|
||||
nations: [],
|
||||
sprachen: [],
|
||||
@@ -131,6 +144,44 @@ export default {
|
||||
verbandEndpoint: ApiStvVerband
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
appMenuExtraItems() {
|
||||
const extraItems = [];
|
||||
|
||||
if (this.studiengangKz !== undefined && this.selected_semester !== undefined) {
|
||||
const studiengang_kz = String(this.studiengangKz);
|
||||
const semester = String(this.selected_semester);
|
||||
const orgform = this.selected_orgform || '';
|
||||
|
||||
extraItems.push({
|
||||
link: FHC_JS_DATA_STORAGE_OBJECT.app_root
|
||||
+ 'content/statistik/notenspiegel.php?type=xls'
|
||||
+ '&studiengang_kz=' + studiengang_kz
|
||||
+ '&semester=' + semester
|
||||
+ '&orgform=' + orgform,
|
||||
description: 'stv/grade_report_xls'
|
||||
});
|
||||
extraItems.push({
|
||||
link: FHC_JS_DATA_STORAGE_OBJECT.app_root
|
||||
+ 'content/statistik/notenspiegel_erweitert.php?typ=xls'
|
||||
+ '&studiengang_kz=' + studiengang_kz
|
||||
+ '&semester=' + semester
|
||||
+ '&orgform=' + orgform,
|
||||
description: 'stv/grade_report_xls_extended'
|
||||
});
|
||||
extraItems.push({
|
||||
link: FHC_JS_DATA_STORAGE_OBJECT.app_root
|
||||
+ 'content/statistik/notenspiegel.php?type=html'
|
||||
+ '&studiengang_kz=' + studiengang_kz
|
||||
+ '&semester=' + semester
|
||||
+ '&orgform=' + orgform,
|
||||
description: 'stv/grade_report_html'
|
||||
});
|
||||
}
|
||||
|
||||
return extraItems;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'url_studiensemester_kurzbz': function (newVal, oldVal) {
|
||||
if (newVal !== oldVal) {
|
||||
@@ -146,6 +197,25 @@ export default {
|
||||
},
|
||||
'url_mode': function () {
|
||||
this.handlePersonUrl();
|
||||
},
|
||||
url_prestudent_id() {
|
||||
this.handlePersonUrl();
|
||||
},
|
||||
'appconfig.font_size'() {
|
||||
// add to html class
|
||||
const classList = Object.keys(this.$refs.config.setup.font_size.options);
|
||||
classList.forEach(cn => document.documentElement.classList.remove(cn));
|
||||
document.documentElement.classList.add(this.appconfig.font_size);
|
||||
// recalc Tabulator heights
|
||||
if (this.$el) {
|
||||
const tabulatorEls = this.$el.querySelectorAll('.tabulator');
|
||||
for (const el of tabulatorEls) {
|
||||
const tabulators = Tabulator.findTable(el);
|
||||
if (tabulators) {
|
||||
tabulators[0].searchRows().forEach(row => row.normalizeHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -159,7 +229,7 @@ export default {
|
||||
}
|
||||
},
|
||||
buildPrestudentSearchResultLink(data) {
|
||||
return this.$fhcApi.getUri(
|
||||
return this.$api.getUri(
|
||||
'/studentenverwaltung'
|
||||
+ '/' + this.studiensemesterKurzbz
|
||||
+ '/prestudent/'
|
||||
@@ -167,7 +237,7 @@ export default {
|
||||
);
|
||||
},
|
||||
buildStudentSearchResultLink(data) {
|
||||
return this.$fhcApi.getUri(
|
||||
return this.$api.getUri(
|
||||
'/studentenverwaltung'
|
||||
+ '/' + this.studiensemesterKurzbz
|
||||
+ '/student/'
|
||||
@@ -175,14 +245,14 @@ export default {
|
||||
);
|
||||
},
|
||||
buildPersonSearchResultLink(data) {
|
||||
return this.$fhcApi.getUri(
|
||||
return this.$api.getUri(
|
||||
'/studentenverwaltung'
|
||||
+ '/' + this.studiensemesterKurzbz
|
||||
+ '/person/'
|
||||
+ data.person_id
|
||||
);
|
||||
},
|
||||
onSelectVerband( {link, studiengang_kz}) {
|
||||
onSelectVerband({ link, studiengang_kz, semester, orgform_kurzbz }) {
|
||||
let urlpath = String(link);
|
||||
if (!urlpath.match(/\/prestudent/))
|
||||
{
|
||||
@@ -191,6 +261,8 @@ export default {
|
||||
this.$refs.stvList.updateUrl(ApiStv.students.verband(urlpath));
|
||||
|
||||
this.studiengangKz = studiengang_kz;
|
||||
this.selected_semester = semester;
|
||||
this.selected_orgform = orgform_kurzbz;
|
||||
const stg = this.lists.stgs.find((element) => {
|
||||
return (element.studiengang_kz === this.studiengangKz);
|
||||
});
|
||||
@@ -249,6 +321,34 @@ export default {
|
||||
ApiStv.students.person(this.$route.params.person_id, 'CURRENT_SEMESTER'),
|
||||
true
|
||||
);
|
||||
} else if (this.$route.params.searchstr) {
|
||||
const searchsettings = {
|
||||
searchstr: this.$route.params.searchstr,
|
||||
types: this.$route.params.types?.split('+') || []
|
||||
};
|
||||
|
||||
// init into student list
|
||||
this.$refs.stvList.updateUrl(
|
||||
ApiStv.students.search(searchsettings, this.studiensemesterKurzbz)
|
||||
);
|
||||
|
||||
// init into searchbar
|
||||
this.$refs.searchbar.searchsettings.searchstr = searchsettings.searchstr;
|
||||
this.$refs.searchbar.searchsettings.types = searchsettings.types;
|
||||
this.$nextTick(this.blurSearchbar);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.clearTabulator();
|
||||
}
|
||||
},
|
||||
clearTabulator() {
|
||||
if(['index', 'studiensemester'].includes(this.$route.name))
|
||||
{
|
||||
if(this.$refs?.stvList?.$refs?.table?.tabulator)
|
||||
{
|
||||
this.$refs.stvList.$refs.table.tabulator.setData([]);
|
||||
}
|
||||
}
|
||||
},
|
||||
checkUrlStudiengang() {
|
||||
@@ -269,6 +369,42 @@ export default {
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.studiengangKz = undefined;
|
||||
this.studiengangKuerzel = '';
|
||||
this.clearTabulator();
|
||||
}
|
||||
},
|
||||
onSearch(e) {
|
||||
const searchsettings = { ...this.$refs.searchbar.searchsettings };
|
||||
if (searchsettings.searchstr.length >= 2) {
|
||||
this.blurSearchbar();
|
||||
|
||||
if (!searchsettings.types.length || searchsettings.types.length == this.$refs.searchbar.types.length) {
|
||||
this.$router.push({
|
||||
name: 'search',
|
||||
params: {
|
||||
studiensemester_kurzbz: this.studiensemesterKurzbz,
|
||||
searchstr: searchsettings.searchstr
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.$router.push({
|
||||
name: 'search_w_types',
|
||||
params: {
|
||||
studiensemester_kurzbz: this.studiensemesterKurzbz,
|
||||
searchstr: searchsettings.searchstr,
|
||||
types: searchsettings.types.join('+')
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
blurSearchbar() {
|
||||
this.$refs.searchbar.$refs.input.blur();
|
||||
this.$refs.searchbar.abort();
|
||||
this.$refs.searchbar.hideresult();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -381,10 +517,58 @@ export default {
|
||||
<span class="fa-solid fa-table-list"></span>
|
||||
</button>
|
||||
<core-searchbar
|
||||
ref="searchbar"
|
||||
:searchoptions="searchbaroptions"
|
||||
:searchfunction="searchfunction"
|
||||
class="searchbar position-relative w-100"
|
||||
show-btn-submit
|
||||
@submit.prevent="onSearch"
|
||||
></core-searchbar>
|
||||
<div id="nav-user" class="dropdown">
|
||||
<button
|
||||
id="nav-user-btn"
|
||||
class="btn btn-link rounded-0 py-0"
|
||||
type="button"
|
||||
data-bs-toggle="dropdown"
|
||||
data-bs-target="#nav-user-menu"
|
||||
aria-expanded="false"
|
||||
aria-controls="nav-user-menu"
|
||||
>
|
||||
<img
|
||||
:src="avatarUrl"
|
||||
:alt="$p.t('profilUpdate/profilBild')"
|
||||
class="bg-light avatar rounded-circle border border-light"
|
||||
/>
|
||||
</button>
|
||||
<ul
|
||||
ref="navUserDropdown"
|
||||
class="dropdown-menu dropdown-menu-dark dropdown-menu-end rounded-0 text-center m-0"
|
||||
aria-labelledby="nav-user-btn"
|
||||
>
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
class="dropdown-item"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#configModal"
|
||||
>
|
||||
{{ $p.t('ui/settings') }}
|
||||
</button>
|
||||
</li>
|
||||
<li><hr class="dropdown-divider m-0"/></li>
|
||||
<li>
|
||||
<nav-language
|
||||
item-class="dropdown-item border-left-dark"
|
||||
/>
|
||||
</li>
|
||||
<li><hr class="dropdown-divider m-0"/></li>
|
||||
<li>
|
||||
<a class="dropdown-item" :href="logoutUrl">
|
||||
{{ $p.t('ui/logout') }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
<div class="container-fluid overflow-hidden">
|
||||
<div class="row h-100">
|
||||
@@ -394,14 +578,38 @@ export default {
|
||||
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" :aria-label="$p.t('ui/schliessen')"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<app-menu app-identifier="stv" />
|
||||
<app-menu app-identifier="stv">
|
||||
<li class="dropend">
|
||||
<a
|
||||
class="dropdown-toggle"
|
||||
href="#"
|
||||
role="button"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
:class="{ disabled: !appMenuExtraItems.length }"
|
||||
data-bs-popper-config='{"strategy":"fixed"}'
|
||||
>
|
||||
{{ $p.t('stv/grade_report') }}
|
||||
</a>
|
||||
<ul class="dropdown-menu p-0">
|
||||
<li
|
||||
v-for="(item, key) in appMenuExtraItems"
|
||||
:key="key"
|
||||
>
|
||||
<a class="dropdown-item" :href="item.link" target="_blank">
|
||||
{{ $p.t(item.description) }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</app-menu>
|
||||
</div>
|
||||
</aside>
|
||||
<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="$p.t('ui/schliessen')"></button>
|
||||
</div>
|
||||
<stv-verband :preselectedKey="'' + studiengangKz" :endpoint="verbandEndpoint" @select-verband="onSelectVerband" class="col" style="height:0%"></stv-verband>
|
||||
<stv-verband :preselectedKey="studiengangKz ? '' + studiengangKz : null" :endpoint="verbandEndpoint" @select-verband="onSelectVerband" class="col" style="height:0%"></stv-verband>
|
||||
<stv-studiensemester v-model:studiensemester-kurzbz="studiensemesterKurzbz" @update:studiensemester-kurzbz="studiensemesterChanged"></stv-studiensemester>
|
||||
</nav>
|
||||
<main class="col-md-8 ms-sm-auto col-lg-9 col-xl-10">
|
||||
@@ -416,5 +624,6 @@ export default {
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
<app-config ref="config" v-model="appconfig" :endpoints="configEndpoints"></app-config>
|
||||
</div>`
|
||||
};
|
||||
|
||||
@@ -41,25 +41,34 @@ export default {
|
||||
return Object.fromEntries(Object.entries(this.configStudents).filter(([ , value ]) => !value.showOnlyWithUid && !value.showOnlyWithUid));
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$p.user_language.value'(n, o) {
|
||||
if (n !== o && o !== undefined)
|
||||
this.loadConfig();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loadConfig() {
|
||||
this.$api
|
||||
.call(ApiStvApp.configStudent())
|
||||
.then(result => {
|
||||
this.configStudent = result.data;
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
this.$api
|
||||
.call(ApiStvApp.configStudents())
|
||||
.then(result => {
|
||||
this.configStudents = result.data;
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
reload() {
|
||||
if (this.$refs.tabs?.$refs?.current?.reload)
|
||||
this.$refs.tabs.$refs.current.reload();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$api
|
||||
.call(ApiStvApp.configStudent())
|
||||
.then(result => {
|
||||
this.configStudent = result.data;
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
this.$api
|
||||
.call(ApiStvApp.configStudents())
|
||||
.then(result => {
|
||||
this.configStudents = result.data;
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
this.loadConfig();
|
||||
},
|
||||
template: `
|
||||
<div class="stv-details h-100 d-flex flex-column">
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
export default {
|
||||
name: "TabCombinePeople",
|
||||
inject: {
|
||||
cisRoot: {
|
||||
from: 'cisRoot'
|
||||
},
|
||||
},
|
||||
props: {
|
||||
modelValue: Object,
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
iframeUrl: null,
|
||||
viewLoaded: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
personIds() {
|
||||
return Array.isArray(this.modelValue)
|
||||
? this.modelValue.map(e => e.person_id)
|
||||
: [this.modelValue.person_id];
|
||||
},
|
||||
detailStringPerson1(){
|
||||
let person1 = this.modelValue[0];
|
||||
return person1.vorname + " " + person1.nachname + "(" + person1.person_id + ")";
|
||||
},
|
||||
detailStringPerson2(){
|
||||
let person2 = this.modelValue[1];
|
||||
return person2.vorname + " " + person2.nachname + "(" + person2.person_id+ ")";
|
||||
},
|
||||
|
||||
},
|
||||
methods: {
|
||||
combinePeople(){
|
||||
this.viewLoaded = true;
|
||||
let person1_id = this.personIds[0];
|
||||
let person2_id = this.personIds[1];
|
||||
|
||||
if(person1_id == person2_id) {
|
||||
return this.$fhcAlert.alertError(this.$p.t('stv', 'error_combinePeople_samePerson'));
|
||||
}
|
||||
|
||||
let linkCombinePeople = this.cisRoot + 'vilesci/stammdaten/personen_wartung.php?person_id_1=' + person1_id + '&person_id_2='+ person2_id;
|
||||
this.openLink(linkCombinePeople);
|
||||
},
|
||||
openLink(url) {
|
||||
this.iframeUrl = url;
|
||||
},
|
||||
goBack(){
|
||||
this.viewLoaded = false;
|
||||
this.iframeUrl = null;
|
||||
}
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div class="stv-details-combine-people h-100 pb-3">
|
||||
|
||||
<div v-if="!this.viewLoaded">
|
||||
<h4>Personen zusammenlegen</h4>
|
||||
<div v-if="this.modelValue.length">
|
||||
<div v-if="this.modelValue.length == 2">
|
||||
<p>{{$p.t('stv', 'question_combine_people', { person1: detailStringPerson1, person2: detailStringPerson2 })}}</p>
|
||||
<button class="btn btn-primary" @click="combinePeople">{{$p.t('ui', 'ok')}}</button>
|
||||
</div>
|
||||
<div v-else>
|
||||
ungültige Anzahl: {{this.modelValue.length}} <!-- should not be seen anymore-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<button class="btn btn-secondary" @click="goBack">{{$p.t('ui', 'cancel')}}</button>
|
||||
</div>
|
||||
|
||||
<!-- Iframe-Section -->
|
||||
<iframe
|
||||
v-if="iframeUrl"
|
||||
:src="iframeUrl"
|
||||
class="w-100 mt-4 border-0"
|
||||
style="height: 600px;"
|
||||
></iframe>
|
||||
|
||||
</div>
|
||||
`
|
||||
};
|
||||
@@ -2,6 +2,8 @@ import {CoreFilterCmpt} from "../../filter/Filter.js";
|
||||
import ListNew from './List/New.js';
|
||||
import ListFilter from './List/Filter.js';
|
||||
|
||||
import { capitalize } from '../../../helpers/StringHelpers.js';
|
||||
|
||||
import draggable from '../../../directives/draggable.js';
|
||||
|
||||
export default {
|
||||
@@ -133,7 +135,12 @@ export default {
|
||||
{
|
||||
return Promise.resolve({ data: []});
|
||||
}
|
||||
return this.$api.call({method: 'post', url, params});
|
||||
/**
|
||||
* NOTE(chris): Because of a bug in Tabulator
|
||||
* we need to get the params from elsewhere.
|
||||
* @see https://github.com/olifolkerd/tabulator/issues/4318
|
||||
*/
|
||||
return this.$api.call({...config, url, params: this.tabulatorOptions.ajaxParams});
|
||||
},
|
||||
ajaxResponse: (url, params, response) => {
|
||||
return response?.data;
|
||||
@@ -228,7 +235,84 @@ export default {
|
||||
return "StudentList_" + today + ".csv";
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$p.user_language.value'(n, o) {
|
||||
if (n !== o && o !== undefined && this.$refs.table.tableBuilt) {
|
||||
this.translateTabulator();
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
translateTabulator() {
|
||||
this.$p
|
||||
.loadCategory(['global', 'person', 'lehre', 'ui', 'profilUpdate', 'admission', 'stv'])
|
||||
.then(() => {
|
||||
const translations = {
|
||||
uid: capitalize(this.$p.t('person/uid')),
|
||||
titelpre: capitalize(this.$p.t('person/titelpre')),
|
||||
nachname: capitalize(this.$p.t('person/nachname')),
|
||||
vorname: capitalize(this.$p.t('person/vorname')),
|
||||
wahlname: capitalize(this.$p.t('person/wahlname')),
|
||||
vornamen: capitalize(this.$p.t('person/vornamen')),
|
||||
titelpost: capitalize(this.$p.t('person/titelpost')),
|
||||
ersatzkennzeichen: capitalize(this.$p.t('person/ersatzkennzeichen')),
|
||||
gebdatum: capitalize(this.$p.t('person/geburtsdatum')),
|
||||
geschlecht: capitalize(this.$p.t('person/geschlecht')),
|
||||
semester: capitalize(this.$p.t('lehre/sem')),
|
||||
verband: capitalize(this.$p.t('lehre/verb')),
|
||||
gruppe: capitalize(this.$p.t('lehre/grp')),
|
||||
studiengang: capitalize(this.$p.t('lehre/studiengang')),
|
||||
studiengang_kz: capitalize(this.$p.t('lehre/studiengang_kz')),
|
||||
matrikelnr: capitalize(this.$p.t('person/personenkennzeichen')),
|
||||
person_id: capitalize(this.$p.t('person/person_id')),
|
||||
status: capitalize(this.$p.t('global/status')),
|
||||
status_datum: capitalize(this.$p.t('profilUpdate/statusDate')),
|
||||
status_bestaetigung: capitalize(this.$p.t('global/status_bestaetigung')),
|
||||
mail_privat: capitalize(this.$p.t('person/email_private')),
|
||||
mail_intern: capitalize(this.$p.t('person/email_intern')),
|
||||
anmerkungen: capitalize(this.$p.t('stv/notes_person')),
|
||||
anmerkung: capitalize(this.$p.t('stv/notes_prestudent')),
|
||||
orgform_kurzbz: capitalize(this.$p.t('lehre/orgform')),
|
||||
aufmerksamdurch_kurzbz: capitalize(this.$p.t('person/aufmerksamDurch')),
|
||||
punkte: capitalize(this.$p.t('admission/gesamtpunkte')),
|
||||
aufnahmegruppe_kurzbz: capitalize(this.$p.t('stv/aufnahmegruppe_kurzbz')),
|
||||
dual: capitalize(this.$p.t('lehre/dual_short')),
|
||||
matr_nr: capitalize(this.$p.t('person/matrikelnummer')),
|
||||
studienplan_bezeichnung: capitalize(this.$p.t('lehre/studienplan')),
|
||||
prestudent_id: capitalize(this.$p.t('ui/prestudent_id')),
|
||||
priorisierung_relativ: capitalize(this.$p.t('lehre/prioritaet')),
|
||||
mentor: capitalize(this.$p.t('stv/mentor')),
|
||||
bnaktiv: capitalize(this.$p.t('person/aktiv'))
|
||||
};
|
||||
|
||||
/** NOTE(chris):
|
||||
* use this approach because updateDefinition
|
||||
* on the Tabulator columns is way slower and
|
||||
* freezes up the GUI.
|
||||
*/
|
||||
// Overwrite definition for column show/hide
|
||||
this.$refs.table.tabulator.getColumns().forEach(col => {
|
||||
const trans = translations[col.getField()];
|
||||
if (!trans)
|
||||
return;
|
||||
col.getDefinition().title = trans;
|
||||
});
|
||||
// Overwrite node in dom
|
||||
this.$refs.table.tabulator.element
|
||||
.querySelectorAll('.tabulator-col[tabulator-field]')
|
||||
.forEach(el => {
|
||||
const field = el.getAttribute('tabulator-field');
|
||||
if (!translations[field])
|
||||
return;
|
||||
|
||||
const title = el.querySelector('.tabulator-col-title');
|
||||
if (!title)
|
||||
return;
|
||||
|
||||
title.innerText = translations[field];
|
||||
});
|
||||
});
|
||||
},
|
||||
reload() {
|
||||
this.$refs.table.reloadTable();
|
||||
},
|
||||
@@ -290,20 +374,22 @@ export default {
|
||||
encodeURIComponent(this.currentSemester)
|
||||
);
|
||||
|
||||
const params = {};
|
||||
const params = (endpoint?.params !== undefined) ? endpoint.params : {};
|
||||
const method = (endpoint?.method !== undefined) ? endpoint.method : 'get';
|
||||
if (this.filter.length)
|
||||
params.filter = this.filter;
|
||||
|
||||
this.tabulatorOptions.ajaxURL = endpoint.url;
|
||||
this.tabulatorOptions.ajaxParams = { ...params };
|
||||
this.tabulatorOptions.ajaxConfig = method;
|
||||
if (!this.$refs.table.tableBuilt) {
|
||||
if (!this.$refs.table.tabulator) {
|
||||
this.tabulatorOptions.ajaxURL = endpoint.url;
|
||||
this.tabulatorOptions.ajaxParams = params;
|
||||
} else
|
||||
if (this.$refs.table.tabulator) {
|
||||
this.$refs.table.tabulator.on("tableBuilt", () => {
|
||||
this.$refs.table.tabulator.setData(endpoint.url, params);
|
||||
this.$refs.table.tabulator.setData(endpoint.url, params, method);
|
||||
});
|
||||
}
|
||||
} else
|
||||
this.$refs.table.tabulator.setData(endpoint.url, params);
|
||||
this.$refs.table.tabulator.setData(endpoint.url, params, method);
|
||||
},
|
||||
dragCleanup(evt) {
|
||||
if (evt.dataTransfer.dropEffect == 'none')
|
||||
@@ -400,6 +486,7 @@ export default {
|
||||
new-btn-show
|
||||
:new-btn-label="$p.t('stv/action_new')"
|
||||
@click:new="actionNewPrestudent"
|
||||
@table-built="translateTabulator"
|
||||
>
|
||||
<template #filter>
|
||||
<div class="card">
|
||||
|
||||
@@ -16,11 +16,17 @@ export default {
|
||||
inject: {
|
||||
$reloadList: {
|
||||
from: '$reloadList',
|
||||
required: true
|
||||
default: () => {}
|
||||
},
|
||||
currentSemester: {
|
||||
from: 'currentSemester',
|
||||
required: true
|
||||
},
|
||||
appConfig: {
|
||||
from: 'appConfig',
|
||||
default: {
|
||||
number_displayed_past_studiensemester: 5
|
||||
}
|
||||
}
|
||||
},
|
||||
emits: [
|
||||
@@ -52,6 +58,9 @@ export default {
|
||||
return this.nodes.filter(node => this.favorites.list.includes(node.key));
|
||||
|
||||
return this.nodes;
|
||||
},
|
||||
noSemReloadNodes() {
|
||||
return this.nodes.reduce(this.mapNodesToNoSemReloadNodes, []);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -59,6 +68,14 @@ export default {
|
||||
if (newVal !== oldVal) {
|
||||
this.setPreselection();
|
||||
}
|
||||
},
|
||||
'appConfig.number_displayed_past_studiensemester'(newVal, oldVal) {
|
||||
if (oldVal !== undefined) {
|
||||
this.noSemReloadNodes.forEach(node => {
|
||||
delete node.children;
|
||||
this.onExpandTreeNode(node);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -114,7 +131,14 @@ export default {
|
||||
},
|
||||
onSelectTreeNode(node) {
|
||||
if (node.data.link)
|
||||
this.$emit('selectVerband', {link: node.data.link, studiengang_kz: node.data.stg_kz});
|
||||
this.$emit('selectVerband', {link: node.data.link, studiengang_kz: node.data.stg_kz, semester: node.data.semester, orgform_kurzbz: node.data.orgform_kurzbz});
|
||||
},
|
||||
mapNodesToNoSemReloadNodes(result, node) {
|
||||
if (node.data.no_sem_reload)
|
||||
result.push(node);
|
||||
if (node.children)
|
||||
result = node.children.reduce(this.mapNodesToNoSemReloadNodes, result);
|
||||
return result;
|
||||
},
|
||||
mapResultToTreeData(el) {
|
||||
const cp = {
|
||||
@@ -187,22 +211,25 @@ export default {
|
||||
if (!currentNode)
|
||||
return;
|
||||
|
||||
const currentSelectedKey = Object.keys(this.selectedKey).find(Boolean);
|
||||
if (currentSelectedKey) {
|
||||
if (currentSelectedKey == currentKey)
|
||||
return;
|
||||
/**
|
||||
* Do not select a new entry if the current is a child of the new one.
|
||||
* This happens if a child entry of a new stg is selected and the router
|
||||
* tries to select the stg root entry (because subtrees do not have
|
||||
* routes yet)
|
||||
*/
|
||||
const isChild = this.findNodeByKey(
|
||||
currentSelectedKey,
|
||||
currentNode.children
|
||||
);
|
||||
if (isChild)
|
||||
return;
|
||||
if(this.selectedKey)
|
||||
{
|
||||
const currentSelectedKey = Object.keys(this.selectedKey).find(Boolean);
|
||||
if (currentSelectedKey) {
|
||||
if (currentSelectedKey == currentKey)
|
||||
return;
|
||||
/**
|
||||
* Do not select a new entry if the current is a child of the new one.
|
||||
* This happens if a child entry of a new stg is selected and the router
|
||||
* tries to select the stg root entry (because subtrees do not have
|
||||
* routes yet)
|
||||
*/
|
||||
const isChild = this.findNodeByKey(
|
||||
currentSelectedKey,
|
||||
currentNode.children || []
|
||||
);
|
||||
if (isChild)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 1; i < parts.length; i++)
|
||||
|
||||
@@ -33,7 +33,8 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
current: null,
|
||||
tabs: {}
|
||||
tabs: {},
|
||||
count: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -113,10 +114,12 @@ export default {
|
||||
};
|
||||
}
|
||||
|
||||
if (Array.isArray(config))
|
||||
if (Array.isArray(config)) {
|
||||
config.forEach((item, key) => _addToTabs(key, item));
|
||||
else
|
||||
}
|
||||
else {
|
||||
Object.entries(config).forEach(([key, item]) => _addToTabs(key, item));
|
||||
}
|
||||
|
||||
if (this.current === null || !tabs[this.current]) {
|
||||
if (tabs[this.default])
|
||||
@@ -129,6 +132,57 @@ export default {
|
||||
updateSuffix() {
|
||||
this.getTabSuffix(this.currentTab);
|
||||
},
|
||||
removeInvalidCountTabs(){
|
||||
if(this.modelValue.length)
|
||||
{
|
||||
let countIst = this.modelValue.length;
|
||||
const tabsToDelete = [];
|
||||
|
||||
Object.entries(this.config).forEach(([key, item]) => {
|
||||
|
||||
const target = item?.config ? item : item?.value || item;
|
||||
|
||||
// check config for validCountMulti
|
||||
if (target.config?.validCountMulti !== undefined) {
|
||||
let tab;
|
||||
let countSoll;
|
||||
tab = key;
|
||||
countSoll = target.config.validCountMulti;
|
||||
|
||||
//check if tab is existing
|
||||
if (countSoll !== undefined && countSoll == countIst) {
|
||||
//add tab if it was removed before
|
||||
if (tab in this.tabs == false) {
|
||||
const value = Vue.reactive({
|
||||
suffix: '',
|
||||
showSuffix: item.showSuffix || false
|
||||
});
|
||||
|
||||
this.tabs[tab] = {
|
||||
component: Vue.markRaw(Vue.defineAsyncComponent(() => import(item.component))),
|
||||
title: Vue.computed(() => item.title || tab),
|
||||
config: item.config,
|
||||
tab,
|
||||
value,
|
||||
suffixhelper: item.suffixhelper ?? null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
//add to toDeleteArray if count is not allowed
|
||||
if (countSoll !== undefined && countSoll !== countIst) {
|
||||
tabsToDelete.push(tab);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Delete all tabs with count not allowed
|
||||
tabsToDelete.forEach(k => {
|
||||
delete this.tabs[k];
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
async getTabSuffix(tab) {
|
||||
if (!tab.value.showSuffix) {
|
||||
return;
|
||||
@@ -151,9 +205,11 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.getTabSuffixes();
|
||||
this.removeInvalidCountTabs();
|
||||
},
|
||||
updated() {
|
||||
this.getTabSuffixes();
|
||||
this.removeInvalidCountTabs();
|
||||
},
|
||||
template: `
|
||||
<template v-if="useprimevue">
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (C) 2025 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/>.
|
||||
*/
|
||||
|
||||
export default {
|
||||
emits: [
|
||||
'changed'
|
||||
],
|
||||
props: {
|
||||
activeClass: {
|
||||
type: String,
|
||||
default: 'active'
|
||||
},
|
||||
itemClass: {
|
||||
type: [String, Array, Object],
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
languages: FHC_JS_DATA_STORAGE_OBJECT.server_languages
|
||||
};
|
||||
},
|
||||
methods:{
|
||||
onChange(lang) {
|
||||
if (this.languages.some(l => l.sprache === lang)) {
|
||||
this.$p
|
||||
.setLanguage(lang)
|
||||
.then(() => {
|
||||
if (document.querySelector('[cis4Reload]'))
|
||||
window.location.reload();
|
||||
else
|
||||
this.$emit('changed', lang);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
template: /*html*/`
|
||||
<div class="navigation-language d-flex justify-content-center align-items-center flex-nowrap overflow-hidden">
|
||||
<button
|
||||
v-for="lang in languages"
|
||||
:class="[itemClass, {[activeClass]: $p.user_language.value == lang.sprache}]"
|
||||
:selected="$p.user_language.value == lang.sprache"
|
||||
@click.prevent="onChange(lang.sprache)"
|
||||
>
|
||||
{{ lang.bezeichnung }}
|
||||
</button>
|
||||
</div>`
|
||||
};
|
||||
@@ -23,7 +23,17 @@ export default {
|
||||
mergedStudent,
|
||||
mergedPerson
|
||||
},
|
||||
props: [ "searchoptions", "searchfunction" ],
|
||||
props: {
|
||||
searchoptions: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
searchfunction: {
|
||||
type: Function,
|
||||
required: true
|
||||
},
|
||||
showBtnSubmit: Boolean
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
query: Vue.computed(() => this.lastQuery)
|
||||
@@ -102,11 +112,22 @@ export default {
|
||||
>
|
||||
<button
|
||||
v-if="searchsettings.searchstr"
|
||||
type="button"
|
||||
class="searchbar_input_clear btn btn-outline-secondary"
|
||||
@click="clearInput"
|
||||
@focusin.stop
|
||||
>
|
||||
<i class="fas fa-close"></i>
|
||||
</button>
|
||||
<button
|
||||
v-if="showBtnSubmit"
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
:title="$p.t('search/submit')"
|
||||
:aria-label="$p.t('search/submit')"
|
||||
>
|
||||
<i class="fas fa-search"></i>
|
||||
</button>
|
||||
<button
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#searchSettings"
|
||||
@@ -219,12 +240,12 @@ export default {
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clearInput() {
|
||||
this.searchsettings.searchstr = "";
|
||||
this.hideresult();
|
||||
this.$refs.input.focus()
|
||||
},
|
||||
methods: {
|
||||
clearInput() {
|
||||
this.searchsettings.searchstr = "";
|
||||
this.hideresult();
|
||||
this.$refs.input.focus();
|
||||
},
|
||||
getInitiallySelectedTypes() {
|
||||
let result = false;
|
||||
if (this.searchoptions.origin) {
|
||||
@@ -283,13 +304,9 @@ export default {
|
||||
this.calcSearchResultHeight();
|
||||
},
|
||||
search: function() {
|
||||
if( this.searchtimer !== null ) {
|
||||
clearTimeout(this.searchtimer);
|
||||
}
|
||||
if (this.abortController) {
|
||||
this.abortController.abort();
|
||||
this.abortController = null;
|
||||
}
|
||||
if(this.searchoptions?.nolivesearch === true) return;
|
||||
|
||||
this.abort();
|
||||
if( this.searchsettings.searchstr.length >= 2 ) {
|
||||
this.calcSearchResultExtent();
|
||||
this.searchtimer = setTimeout(
|
||||
@@ -300,6 +317,16 @@ export default {
|
||||
this.showresult = false;
|
||||
}
|
||||
},
|
||||
abort() {
|
||||
if (this.searchtimer !== null) {
|
||||
clearTimeout(this.searchtimer);
|
||||
}
|
||||
if (this.abortController) {
|
||||
this.abortController.abort();
|
||||
this.abortController = null;
|
||||
}
|
||||
this.searchresult = [];
|
||||
},
|
||||
callsearchapi: function() {
|
||||
this.error = null;
|
||||
this.searchresult.splice(0, this.searchresult.length);
|
||||
@@ -392,6 +419,8 @@ export default {
|
||||
window.removeEventListener('resize', this.calcSearchResultExtent);
|
||||
},
|
||||
showsearchresult: function() {
|
||||
if(this.searchoptions?.nolivesearch === true) return;
|
||||
|
||||
if( this.searchsettings.searchstr.length >= 2 ) {
|
||||
this.showresult = true;
|
||||
window.addEventListener('resize', this.calcSearchResultExtent);
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* v-tooltip - This directive makes it easy to initialize Bootstrap tooltips in Vue.
|
||||
*
|
||||
* Features:
|
||||
* - Automatically initializes a Bootstrap tooltip on mount.
|
||||
* - Re-initializes only when the bound value changes.
|
||||
* - Cleans up the tooltip on unmount.
|
||||
|
||||
* Usage examples:
|
||||
*
|
||||
* 1) Shortest way:
|
||||
* <span v-tooltip title="Static tooltip">
|
||||
* Hover me!
|
||||
* </span>
|
||||
*
|
||||
* 2) With binding value. New value will trigger update features (destroy old + create new tooltip creation)
|
||||
* <span v-tooltip="userInfo" :title="userInfo">
|
||||
* Hover me!
|
||||
* </span>
|
||||
*
|
||||
* 3) Allowing HTML inside tooltip:
|
||||
* <span v-tooltip title="<b>Bold text</b>" data-bs-html="true">
|
||||
* Hover me!
|
||||
* </span>
|
||||
*
|
||||
*/
|
||||
export default {
|
||||
mounted(el, binding) {
|
||||
const opts = {
|
||||
title: binding.value ?? el.getAttribute('title'), // fallback if no binding
|
||||
html: el.getAttribute('data-bs-html') === 'true',
|
||||
customClass: el.getAttribute('data-bs-custom-class') || ''
|
||||
};
|
||||
|
||||
// Create tooltip
|
||||
el._tooltip = new bootstrap.Tooltip(el, opts);
|
||||
},
|
||||
updated(el, binding) {
|
||||
// Only dispose and create new Tooltip if value (the title-string) has changed
|
||||
if (binding.value !== binding.oldValue){
|
||||
|
||||
if (el._tooltip) {
|
||||
el._tooltip.dispose();
|
||||
}
|
||||
|
||||
const opts = {
|
||||
title: binding.value ?? el.getAttribute('title'), // fallback if no binding
|
||||
html: el.getAttribute('data-bs-html') === 'true',
|
||||
customClass: el.getAttribute('data-bs-custom-class') || ''
|
||||
};
|
||||
|
||||
el._tooltip = new bootstrap.Tooltip(el, opts);
|
||||
}
|
||||
},
|
||||
unmounted(el) {
|
||||
// Cleanup
|
||||
if (el._tooltip) {
|
||||
el._tooltip.dispose();
|
||||
delete el._tooltip;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,6 +85,7 @@ require_once('dbupdate_3.4/66982_berufsschule.php');
|
||||
require_once('dbupdate_3.4/40314_electronic_onboarding_anbindung_ida.php');
|
||||
require_once('dbupdate_3.4/47972_pruefungsverwaltung_ects_angabe.php');
|
||||
require_once('dbupdate_3.4/67490_studstatus_suche_abort_controller_haengt.php');
|
||||
require_once('dbupdate_3.4/68744_StV_settings.php');
|
||||
|
||||
// *** Pruefung und hinzufuegen der neuen Attribute und Tabellen
|
||||
echo '<H2>Pruefe Tabellen und Attribute!</H2>';
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
if (!defined('DB_NAME')) exit('No direct script access allowed');
|
||||
|
||||
// Add new name type in public.tbl_variablenname
|
||||
if ($result = @$db->db_query("SELECT 1 FROM public.tbl_variablenname WHERE name = 'stv_font_size';"))
|
||||
{
|
||||
if ($db->db_num_rows($result) == 0)
|
||||
{
|
||||
$qry = "INSERT INTO public.tbl_variablenname(name, defaultwert) VALUES('stv_font_size', null);";
|
||||
|
||||
if (!$db->db_query($qry))
|
||||
echo '<strong>public.tbl_variablenname '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo 'public.tbl_variablenname: Added name "stv_font_size"<br>';
|
||||
}
|
||||
}
|
||||
@@ -1795,6 +1795,66 @@ $phrases = array(
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'logout',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Logout',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Logout',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'settings',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Einstellungen',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Settings',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'settings_saved',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Einstellungen gespeichert',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Settings saved',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'ui',
|
||||
@@ -2542,6 +2602,46 @@ $phrases = array(
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'person',
|
||||
'phrase' => 'email_private',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'EMail (Privat)',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'email (private)',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'person',
|
||||
'phrase' => 'email_intern',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'EMail (Intern)',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'email (intern)',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'person',
|
||||
@@ -3124,6 +3224,26 @@ $phrases = array(
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'lehre',
|
||||
'phrase' => 'orgform',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'OrgForm',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'orgform',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'lehre',
|
||||
@@ -3164,6 +3284,26 @@ $phrases = array(
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'lehre',
|
||||
'phrase' => 'grp',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Grp.',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'grp.',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'lehre',
|
||||
@@ -3504,6 +3644,26 @@ $phrases = array(
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'lehre',
|
||||
'phrase' => 'sem',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Sem.',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'sem.',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'lehre',
|
||||
@@ -3786,6 +3946,66 @@ $phrases = array(
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'lehre',
|
||||
'phrase' => 'studiengang_kz',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Studiengang KZ',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Study program no',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'lehre',
|
||||
'phrase' => 'verb',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Verb.',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'assoc.',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'lehre',
|
||||
'phrase' => 'dual_short',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Dual',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'dual',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
//********************** INFOCENTER/infocenter
|
||||
array(
|
||||
'app' => 'infocenter',
|
||||
@@ -6421,6 +6641,26 @@ The invoice will be sent to you again. <u><strong>The amount is only to be trans
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'global',
|
||||
'phrase' => 'status_bestaetigung',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Status Bestätigung',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Status confirmation',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'global',
|
||||
@@ -38680,6 +38920,166 @@ array(
|
||||
)
|
||||
),
|
||||
//**************************** CORE/stv
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'settings_no_displayed_past_sem',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Anzahl angezeigter vergangender Studiensemester',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Number of past semesters of study displayed',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'settings_fontsize',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Zoom',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Zoom',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'settings_fontsize_xx-small',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Sehr Klein',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Very Small',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'settings_fontsize_x-small',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Kleiner',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Smaller',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'settings_fontsize_small',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Klein',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Small',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'settings_fontsize_normal',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Normal',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Normal',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'settings_fontsize_big',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Groß',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Big',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'settings_fontsize_huge',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Sehr groß',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Very big',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
@@ -38700,6 +39100,86 @@ array(
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'notes_person',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Anmerkungen',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'notes',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'notes_prestudent',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Anmerkung Pre',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'note Pre',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'aufnahmegruppe_kurzbz',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Aufnahmegruppe',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'admission group',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'mentor',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Mentor',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'mentor',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
@@ -38880,6 +39360,86 @@ array(
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'grade_report',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Notenspiegel',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Grade report',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'grade_report_xls',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Notenspiegel EXCEL',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Grade report EXCEL',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'grade_report_xls_extended',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Notenspiegel erweitert EXCEL',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Grade report extended EXCEL',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'grade_report_html',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Notenspiegel HTML',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Grade report HTML',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
@@ -49211,6 +49771,26 @@ and represent the current state of research on the topic. The prescribed citatio
|
||||
// FHC-4 Finetuning END
|
||||
|
||||
//**************************** CORE/search
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'search',
|
||||
'phrase' => 'submit',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'suchen',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'search',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'search',
|
||||
@@ -51668,6 +52248,68 @@ I have been informed that I am under no obligation to consent to the transmissio
|
||||
)
|
||||
),
|
||||
// ### DOKUMENTE ERSTELLEN PHRASEN END ###
|
||||
// ### Personen zusammenlegen Phrasen BEGIN
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'tab_combine_people',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Personen zusammenlegen',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Combine People',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'question_combine_people',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Die Personen {person1} und {person2} zusammenlegen?',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Merge the persons {person1} and {person2}?',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'error_combinePeople_samePerson',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Keine Zusammenlegung möglich bei identischer Person ID!',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'No merging possible with identical person ID"',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
// ### Personen zusammenlegen Phrasen END
|
||||
);
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user