Files
minmal-file-cloud-email-pim…/frontend/src/views/LoginView.vue
T
Stefan Hacker 35099de2c5 feat: Share-Dialog Fix, User-Sharing, Admin-Benutzerverwaltung, Registrierungs-Toggle
- Fix: Share-Dialog oeffnet sich jetzt auch bei bereits geteilten Dateien
- Neu: Dateien/Ordner direkt mit anderen Benutzern teilen (Lesen/Schreiben/Admin)
- Neu: Benutzersuche im Share-Dialog, bestehende Freigaben anzeigen/entfernen
- Neu: Admin kann Benutzer ueber die Weboberflaeche anlegen
- Neu: Admin kann Benutzer bearbeiten (Rolle, Quota, aktiv/inaktiv) und loeschen
- Neu: Schieberegler fuer oeffentliche Registrierung in den Admin-Einstellungen
- Neu: Register-Link auf Login-Seite nur sichtbar wenn Registrierung erlaubt
- Neu: Register-Seite leitet um wenn Registrierung deaktiviert
- Neu: AppSettings-Model fuer persistente App-Konfiguration
- Neu: /api/users/search Endpunkt fuer Benutzersuche in Share-Dialogen

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 15:26:04 +02:00

156 lines
3.3 KiB
Vue

<template>
<div class="auth-container">
<div class="auth-card">
<div class="auth-header">
<i class="pi pi-cloud" style="font-size: 2.5rem; color: var(--p-primary-color)"></i>
<h1>Mini-Cloud</h1>
<p>Anmelden</p>
</div>
<form @submit.prevent="handleLogin" class="auth-form">
<div class="field">
<label for="username">Benutzername</label>
<InputText
id="username"
v-model="username"
placeholder="Benutzername"
:invalid="!!error"
autofocus
fluid
/>
</div>
<div class="field">
<label for="password">Passwort</label>
<Password
id="password"
v-model="password"
placeholder="Passwort"
:feedback="false"
:invalid="!!error"
toggle-mask
fluid
/>
</div>
<Message v-if="error" severity="error" :closable="false">{{ error }}</Message>
<Button
type="submit"
label="Anmelden"
:loading="loading"
fluid
/>
</form>
<div v-if="registrationAllowed" class="auth-footer">
<router-link to="/register">Noch kein Konto? Registrieren</router-link>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useAuthStore } from '../stores/auth'
import axios from 'axios'
import InputText from 'primevue/inputtext'
import Password from 'primevue/password'
import Button from 'primevue/button'
import Message from 'primevue/message'
const router = useRouter()
const auth = useAuthStore()
const username = ref('')
const password = ref('')
const error = ref('')
const loading = ref(false)
const registrationAllowed = ref(false)
onMounted(async () => {
try {
const res = await axios.get('/api/auth/registration-status')
registrationAllowed.value = res.data.allowed
} catch { registrationAllowed.value = false }
})
async function handleLogin() {
error.value = ''
loading.value = true
try {
await auth.login(username.value, password.value)
router.push('/')
} catch (err) {
error.value = err.response?.data?.error || 'Anmeldung fehlgeschlagen'
} finally {
loading.value = false
}
}
</script>
<style scoped>
.auth-container {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: var(--p-surface-50);
}
.auth-card {
background: var(--p-surface-0);
border-radius: 12px;
padding: 2.5rem;
width: 100%;
max-width: 400px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
}
.auth-header {
text-align: center;
margin-bottom: 2rem;
}
.auth-header h1 {
margin: 0.5rem 0 0.25rem;
font-size: 1.5rem;
}
.auth-header p {
color: var(--p-text-muted-color);
margin: 0;
}
.auth-form .field {
margin-bottom: 1rem;
}
.auth-form .field label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
font-size: 0.875rem;
}
.auth-form button {
margin-top: 0.5rem;
}
.auth-footer {
text-align: center;
margin-top: 1.5rem;
font-size: 0.875rem;
}
.auth-footer a {
color: var(--p-primary-color);
text-decoration: none;
}
.auth-footer a:hover {
text-decoration: underline;
}
</style>