Add member transfer configuration and UI enhancements
Introduced MemberTransferConfig model and integrated it into the backend, allowing for the storage and retrieval of member transfer settings. Updated server routes to include member transfer configuration endpoints. Enhanced the frontend with a new MemberTransferDialog component for user interaction, added a dedicated route for member transfer settings, and updated the App.vue to include a link for accessing these settings. Improved the loading state and configuration handling in the dialog for better user experience.
This commit is contained in:
@@ -22,6 +22,10 @@
|
||||
<span class="dropdown-icon">🔐</span>
|
||||
Berechtigungen
|
||||
</router-link>
|
||||
<router-link v-if="hasPermission('members', 'write')" to="/member-transfer-settings" class="dropdown-item" @click="userDropdownOpen = false">
|
||||
<span class="dropdown-icon">📤</span>
|
||||
Mitgliederübertragung
|
||||
</router-link>
|
||||
<router-link v-if="isAdmin" to="/logs" class="dropdown-item" @click="userDropdownOpen = false">
|
||||
<span class="dropdown-icon">📋</span>
|
||||
System-Logs
|
||||
|
||||
@@ -7,20 +7,41 @@
|
||||
:close-on-overlay="false"
|
||||
@close="handleClose"
|
||||
>
|
||||
<div class="transfer-form">
|
||||
<div v-if="loadingConfig" class="loading-config">
|
||||
Gespeicherte Konfiguration wird geladen...
|
||||
</div>
|
||||
|
||||
<div v-else class="transfer-form">
|
||||
<div class="form-section">
|
||||
<h4>Server-Konfiguration</h4>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="server">Server-Basis-URL:</label>
|
||||
<input
|
||||
type="text"
|
||||
id="server"
|
||||
v-model="config.server"
|
||||
placeholder="https://example.com"
|
||||
class="form-input"
|
||||
readonly
|
||||
/>
|
||||
<span class="hint">Aus Einstellungen geladen (nur lesend)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<h4>Login-Konfiguration</h4>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="loginEndpoint">Login-Endpoint URL:</label>
|
||||
<label for="loginEndpoint">Login-Endpoint Pfad:</label>
|
||||
<input
|
||||
type="text"
|
||||
id="loginEndpoint"
|
||||
v-model="config.loginEndpoint"
|
||||
placeholder="https://example.com/api/login"
|
||||
placeholder="/api/auth/login"
|
||||
class="form-input"
|
||||
/>
|
||||
<span class="hint">Optional: Falls für die Übertragung ein Login erforderlich ist</span>
|
||||
<span class="hint">Optional: Relativer Pfad zum Login-Endpoint</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@@ -71,17 +92,18 @@
|
||||
<div class="form-section">
|
||||
<h4>Übertragungs-Konfiguration</h4>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="transferEndpoint">Übertragungs-Endpoint URL: <span class="required">*</span></label>
|
||||
<input
|
||||
type="text"
|
||||
id="transferEndpoint"
|
||||
v-model="config.transferEndpoint"
|
||||
placeholder="https://example.com/api/members"
|
||||
class="form-input"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="transferEndpoint">Übertragungs-Endpoint Pfad: <span class="required">*</span></label>
|
||||
<input
|
||||
type="text"
|
||||
id="transferEndpoint"
|
||||
v-model="config.transferEndpoint"
|
||||
placeholder="/api/members/bulk"
|
||||
class="form-input"
|
||||
required
|
||||
/>
|
||||
<span class="hint">Relativer Pfad zum Übertragungs-Endpoint</span>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
@@ -182,7 +204,7 @@ export default {
|
||||
...mapGetters(['currentClub']),
|
||||
|
||||
isValid() {
|
||||
return !!(this.config.transferEndpoint && this.config.transferTemplate);
|
||||
return !!(this.config.server && this.config.transferEndpoint && this.config.transferTemplate);
|
||||
},
|
||||
|
||||
additionalField1Placeholder() {
|
||||
@@ -213,6 +235,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
config: {
|
||||
server: '',
|
||||
loginEndpoint: '',
|
||||
loginFormat: 'json',
|
||||
transferEndpoint: '',
|
||||
@@ -227,10 +250,57 @@ export default {
|
||||
additionalField1: '',
|
||||
additionalField2: ''
|
||||
},
|
||||
isTransferring: false
|
||||
isTransferring: false,
|
||||
loadingConfig: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
modelValue(newVal) {
|
||||
if (newVal) {
|
||||
this.loadSavedConfig();
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async loadSavedConfig() {
|
||||
if (!this.currentClub) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadingConfig = true;
|
||||
try {
|
||||
const response = await apiClient.get(`/member-transfer-config/${this.currentClub}`);
|
||||
|
||||
if (response.data.success && response.data.config) {
|
||||
const savedConfig = response.data.config;
|
||||
|
||||
// Konfiguration aus gespeicherten Daten laden
|
||||
this.config.server = savedConfig.server || '';
|
||||
this.config.loginEndpoint = savedConfig.loginEndpoint || '';
|
||||
this.config.loginFormat = savedConfig.loginFormat || 'json';
|
||||
this.config.transferEndpoint = savedConfig.transferEndpoint || '';
|
||||
this.config.transferMethod = savedConfig.transferMethod || 'POST';
|
||||
this.config.transferFormat = savedConfig.transferFormat || 'json';
|
||||
this.config.transferTemplate = savedConfig.transferTemplate || '';
|
||||
this.config.useBulkMode = savedConfig.useBulkMode || false;
|
||||
|
||||
// Login-Credentials (Passwort wird nicht zurückgegeben, nur wenn vorhanden)
|
||||
if (savedConfig.loginCredentials) {
|
||||
this.loginCredentials.username = savedConfig.loginCredentials.username || '';
|
||||
this.loginCredentials.password = ''; // Passwort wird nicht zurückgegeben
|
||||
// Zusätzliche Felder können nicht direkt zugewiesen werden, da sie verschlüsselt sind
|
||||
// Benutzer muss diese neu eingeben
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Keine Konfiguration vorhanden - das ist OK, Dialog bleibt leer
|
||||
if (error.response?.status !== 404) {
|
||||
console.error('Fehler beim Laden der gespeicherten Konfiguration:', error);
|
||||
}
|
||||
} finally {
|
||||
this.loadingConfig = false;
|
||||
}
|
||||
},
|
||||
handleClose() {
|
||||
this.$emit('update:modelValue', false);
|
||||
this.resetForm();
|
||||
@@ -238,6 +308,7 @@ export default {
|
||||
|
||||
resetForm() {
|
||||
this.config = {
|
||||
server: '',
|
||||
loginEndpoint: '',
|
||||
loginFormat: 'json',
|
||||
transferEndpoint: '',
|
||||
@@ -295,14 +366,20 @@ export default {
|
||||
transferEndpoint: this.config.transferEndpoint,
|
||||
transferMethod: this.config.transferMethod,
|
||||
transferFormat: this.config.transferFormat,
|
||||
transferTemplate: this.config.transferTemplate
|
||||
transferTemplate: this.config.transferTemplate,
|
||||
useBulkMode: this.config.useBulkMode
|
||||
};
|
||||
|
||||
// Login-Konfiguration nur hinzufügen, wenn Endpoint vorhanden
|
||||
if (this.config.loginEndpoint) {
|
||||
transferConfig.loginEndpoint = this.config.loginEndpoint;
|
||||
transferConfig.loginFormat = this.config.loginFormat;
|
||||
transferConfig.loginCredentials = loginCredentials;
|
||||
|
||||
// Nur Login-Credentials hinzufügen, wenn welche eingegeben wurden
|
||||
// Wenn keine eingegeben wurden, werden die gespeicherten verwendet (Backend holt diese)
|
||||
if (Object.keys(loginCredentials).length > 0) {
|
||||
transferConfig.loginCredentials = loginCredentials;
|
||||
}
|
||||
}
|
||||
|
||||
const response = await apiClient.post(
|
||||
@@ -401,6 +478,12 @@ export default {
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.form-input[readonly] {
|
||||
background-color: #f8f9fa;
|
||||
cursor: not-allowed;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.form-textarea {
|
||||
font-family: 'Courier New', monospace;
|
||||
resize: vertical;
|
||||
@@ -489,6 +572,12 @@ export default {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.loading-config {
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
|
||||
@@ -17,6 +17,7 @@ import MyTischtennisAccount from './views/MyTischtennisAccount.vue';
|
||||
import TeamManagementView from './views/TeamManagementView.vue';
|
||||
import PermissionsView from './views/PermissionsView.vue';
|
||||
import LogsView from './views/LogsView.vue';
|
||||
import MemberTransferSettingsView from './views/MemberTransferSettingsView.vue';
|
||||
import Impressum from './views/Impressum.vue';
|
||||
import Datenschutz from './views/Datenschutz.vue';
|
||||
|
||||
@@ -39,6 +40,7 @@ const routes = [
|
||||
{ path: '/team-management', component: TeamManagementView },
|
||||
{ path: '/permissions', component: PermissionsView },
|
||||
{ path: '/logs', component: LogsView },
|
||||
{ path: '/member-transfer-settings', component: MemberTransferSettingsView },
|
||||
{ path: '/impressum', component: Impressum },
|
||||
{ path: '/datenschutz', component: Datenschutz },
|
||||
];
|
||||
|
||||
1206
frontend/src/views/MemberTransferSettingsView.vue
Normal file
1206
frontend/src/views/MemberTransferSettingsView.vue
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user