Änderung: Erweiterung der Benutzer- und Rechteverwaltung im Admin-Bereich

Änderungen:
- Neue Funktionen zur Benutzerverwaltung hinzugefügt: Benutzer suchen, Benutzer abrufen und Benutzer aktualisieren.
- Implementierung von Funktionen zur Verwaltung von Benutzerrechten: Rechtearten auflisten, Benutzerrechte auflisten, Recht hinzufügen und Recht entfernen.
- Routen für die neuen Funktionen im Admin-Router definiert.
- Übersetzungen für Benutzer- und Rechteverwaltung in den Sprachdateien aktualisiert.

Diese Anpassungen verbessern die Verwaltung von Benutzern und deren Rechten im Admin-Bereich und erweitern die Funktionalität der Anwendung.
This commit is contained in:
Torsten Schulz (local)
2025-09-12 09:13:22 +02:00
parent 7decc4c4ae
commit 550b4b5fcb
9 changed files with 440 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
<template>
<div class="admin-user-search">
<div class="search">
<input v-model="q" type="text" :placeholder="$t('admin.user.name')" @keyup.enter="search" />
<button @click="search">{{ $t('admin.user.search') }}</button>
</div>
<div v-if="results.length" class="results">
<ul>
<li v-for="u in results" :key="u.id" @click="$emit('select', u)">{{ u.username }}</li>
</ul>
</div>
</div>
</template>
<script>
import apiClient from '@/utils/axios.js';
export default {
name: 'AdminUserSearch',
emits: ['select'],
data() {
return { q: '', results: [] };
},
methods: {
async search() {
const res = await apiClient.get('/api/admin/users/search', { params: { q: this.q } });
this.results = res.data || [];
}
}
};
</script>
<style scoped>
.admin-user-search { display: grid; gap: 8px; }
.search { display: flex; gap: 8px; }
ul { list-style: none; padding: 0; margin: 0; }
li { padding: 6px 8px; border: 1px solid #ddd; margin-bottom: 6px; cursor: pointer; }
li:hover { background: #f5f5f5; }
</style>

View File

@@ -23,6 +23,18 @@
"editcontactrequest": {
"title": "[Admin] - Kontaktanfrage bearbeiten"
},
"user": {
"name": "Benutzername",
"active": "Aktiv",
"blocked": "Gesperrt",
"actions": "Aktionen",
"search": "Suchen"
},
"rights": {
"add": "Recht hinzufügen",
"select": "Bitte wählen",
"current": "Aktuelle Rechte"
},
"forum": {
"title": "[Admin] - Forum",
"currentForums": "Existierende Foren",

View File

@@ -1,5 +1,17 @@
{
"admin": {
"user": {
"name": "Username",
"active": "Active",
"blocked": "Blocked",
"actions": "Actions",
"search": "Search"
},
"rights": {
"add": "Add right",
"select": "Please select",
"current": "Current rights"
},
"match3": {
"title": "Manage Match3 Levels",
"newLevel": "Create New Level",

View File

@@ -1,9 +1,11 @@
import AdminInterestsView from '../views/admin/InterestsView.vue';
import AdminContactsView from '../views/admin/ContactsView.vue';
import RoomsView from '../views/admin/RoomsView.vue';
import UserRightsView from '../views/admin/UserRightsView.vue';
import ForumAdminView from '../dialogues/admin/ForumAdminView.vue';
import AdminFalukantEditUserView from '../views/admin/falukant/EditUserView.vue';
import AdminMinigamesView from '../views/admin/MinigamesView.vue';
import AdminUsersView from '../views/admin/UsersView.vue';
const adminRoutes = [
{
@@ -12,12 +14,24 @@ const adminRoutes = [
component: AdminInterestsView,
meta: { requiresAuth: true }
},
{
path: '/admin/users',
name: 'AdminUsers',
component: AdminUsersView,
meta: { requiresAuth: true }
},
{
path: '/admin/contacts',
name: 'AdminContacts',
component: AdminContactsView,
meta: { requiresAuth: true }
},
{
path: '/admin/rights',
name: 'AdminUserRights',
component: UserRightsView,
meta: { requiresAuth: true }
},
{
path: '/admin/forum',
name: 'AdminForums',

View File

@@ -0,0 +1,87 @@
<template>
<div class="user-rights-view">
<h1>{{ $t('navigation.m-administration.userrights') }}</h1>
<AdminUserSearch @select="selectUser" />
<div v-if="selected" class="editor">
<h2>{{ selected.username }}</h2>
<div class="assign">
<label>{{ $t('admin.rights.add') }}</label>
<select v-model.number="newRightId">
<option :value="0">{{ $t('admin.rights.select') }}</option>
<option v-for="t in rightTypes" :key="t.id" :value="t.id">{{ t.title }}</option>
</select>
<button :disabled="!newRightId" @click="addRight">{{ $t('common.add') }}</button>
</div>
<h3>{{ $t('admin.rights.current') }}</h3>
<ul class="rights">
<li v-for="r in rights" :key="r.rightTypeId">
{{ r.title }}
<button class="remove" @click="removeRight(r.rightTypeId)">{{ $t('common.delete') }}</button>
</li>
</ul>
</div>
</div>
</template>
<script>
import apiClient from '@/utils/axios.js';
import AdminUserSearch from '@/components/admin/AdminUserSearch.vue';
export default {
name: 'UserRightsView',
components: { AdminUserSearch },
data() {
return {
loading: false,
selected: null,
rightTypes: [],
rights: [],
newRightId: 0
};
},
async mounted() {
await this.loadRightTypes();
}
,
methods: {
async loadRightTypes() {
try {
const res = await apiClient.get('/api/admin/rights/types');
this.rightTypes = res.data || [];
} catch (e) {
console.error('Fehler beim Laden der Rechte-Typen:', e);
}
},
async selectUser(u) {
this.selected = u;
const res = await apiClient.get(`/api/admin/rights/${u.id}`);
this.rights = res.data || [];
this.newRightId = 0;
},
async addRight() {
if (!this.selected || !this.newRightId) return;
await apiClient.post(`/api/admin/rights/${this.selected.id}`, { rightTypeId: this.newRightId });
await this.selectUser(this.selected);
},
async removeRight(rightTypeId) {
if (!this.selected) return;
await apiClient.delete(`/api/admin/rights/${this.selected.id}`, { data: { rightTypeId } });
await this.selectUser(this.selected);
}
}
};
</script>
<style scoped>
.user-rights-view { padding: 20px; }
.content { margin-top: 10px; }
.loading, .empty { color: #666; }
.rights-table { width: 100%; border-collapse: collapse; }
.rights-table th, .rights-table td { border: 1px solid #ddd; padding: 8px; text-align: left; }
.rights-table th { background: #f5f5f5; }
</style>

View File

@@ -0,0 +1,68 @@
<template>
<div class="admin-users">
<h1>{{ $t('navigation.m-administration.useradministration') }}</h1>
<AdminUserSearch @select="select" />
<div v-if="selected" class="edit">
<h2>{{ selected.username }}</h2>
<label>
{{ $t('admin.user.name') }}
<input v-model="form.username" type="text" />
</label>
<label>
{{ $t('admin.user.blocked') }}
<input type="checkbox" :checked="!form.active" @change="toggleBlocked($event)" />
</label>
<div class="actions">
<button @click="save">{{ $t('common.save') }}</button>
</div>
</div>
</div>
</template>
<script>
import apiClient from '@/utils/axios.js';
import AdminUserSearch from '@/components/admin/AdminUserSearch.vue';
export default {
name: 'AdminUsersView',
components: { AdminUserSearch },
data() {
return {
selected: null,
form: { username: '', active: true }
};
},
methods: {
async select(u) {
const res = await apiClient.get(`/api/admin/users/${u.id}`);
this.selected = res.data;
this.form.username = res.data.username;
this.form.active = !!res.data.active;
},
toggleBlocked(e) {
this.form.active = !e.target.checked;
},
async save() {
if (!this.selected) return;
await apiClient.put(`/api/admin/users/${this.selected.id}`, {
username: this.form.username,
active: this.form.active
});
this.$root?.$refs?.messageDialog?.open?.('tr:common.saved');
}
}
};
</script>
<style scoped>
.admin-users { padding: 20px; }
.results table { width: 100%; border-collapse: collapse; }
.results th, .results td { border: 1px solid #ddd; padding: 8px; }
.edit { margin-top: 16px; display: grid; gap: 10px; max-width: 480px; }
.actions { display: flex; gap: 8px; }
button { cursor: pointer; }
</style>