- Nuxt 3 CSR (ssr:false), @nuxtjs/tailwindcss, dev proxy to backend - useAuth composable: CSRF cookie, XSRF token, login/logout/fetchUser - auth middleware: redirects to /login if no session - Login page, client list with search + create modal - Client detail with editable name, dynamic notes (JSON), history feed - History form with type select, inline edit/delete per entry - Print layout at /clients/:id/print (calls window.print on mount) - TypeScript interfaces: User, Client, HistoryEntry, PaginatedResponse - German UI labels throughout Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
61 lines
1.8 KiB
Vue
61 lines
1.8 KiB
Vue
<script setup lang="ts">
|
|
const { login, user } = useAuth()
|
|
|
|
if (user.value) {
|
|
await navigateTo('/clients')
|
|
}
|
|
|
|
const email = ref('')
|
|
const password = ref('')
|
|
const error = ref('')
|
|
const loading = ref(false)
|
|
|
|
const submit = async () => {
|
|
error.value = ''
|
|
loading.value = true
|
|
try {
|
|
await login(email.value, password.value)
|
|
await navigateTo('/clients')
|
|
} catch {
|
|
error.value = 'E-Mail oder Passwort ungültig.'
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="min-h-screen flex items-center justify-center bg-gray-100">
|
|
<div class="bg-white shadow p-8 w-full max-w-sm">
|
|
<h1 class="text-xl font-semibold mb-6">Mandant CRM — Anmeldung</h1>
|
|
<form @submit.prevent="submit" class="space-y-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">E-Mail</label>
|
|
<input
|
|
v-model="email"
|
|
type="email"
|
|
required
|
|
class="mt-1 block w-full border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">Passwort</label>
|
|
<input
|
|
v-model="password"
|
|
type="password"
|
|
required
|
|
class="mt-1 block w-full border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500"
|
|
/>
|
|
</div>
|
|
<p v-if="error" class="text-sm text-red-600">{{ error }}</p>
|
|
<button
|
|
type="submit"
|
|
:disabled="loading"
|
|
class="w-full bg-blue-600 text-white py-2 text-sm font-medium hover:bg-blue-700 disabled:opacity-50"
|
|
>
|
|
{{ loading ? 'Wird angemeldet…' : 'Anmelden' }}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</template>
|