frontend: Owner management
This commit is contained in:
parent
9df2ee08d2
commit
994ba0bc01
8 changed files with 293 additions and 27 deletions
64
frontend/app/pages/login.vue
Normal file
64
frontend/app/pages/login.vue
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from "vue"
|
||||
|
||||
const username = ref("")
|
||||
const password = ref("")
|
||||
const error = ref("")
|
||||
|
||||
const { setToken } = useAuth()
|
||||
const { apiFetch } = useApi()
|
||||
const router = useRouter()
|
||||
|
||||
async function login() {
|
||||
error.value = ""
|
||||
|
||||
try {
|
||||
const data = await apiFetch("/auth/token", {
|
||||
method: "POST",
|
||||
body: new URLSearchParams({
|
||||
username: username.value,
|
||||
password: password.value
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
}
|
||||
})
|
||||
|
||||
setToken(data.access_token)
|
||||
router.push("/")
|
||||
} catch (e: any) {
|
||||
error.value = "Login fehlgeschlagen"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="max-w-sm mx-auto mt-20 p-6 bg-white shadow rounded">
|
||||
<h1 class="text-2xl font-bold mb-4">Login</h1>
|
||||
|
||||
<div class="space-y-4">
|
||||
<input
|
||||
v-model="username"
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
class="w-full p-2 border rounded"
|
||||
/>
|
||||
|
||||
<input
|
||||
v-model="password"
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
class="w-full p-2 border rounded"
|
||||
/>
|
||||
|
||||
<button
|
||||
@click="login"
|
||||
class="w-full bg-blue-600 text-white p-2 rounded hover:bg-blue-700"
|
||||
>
|
||||
Login
|
||||
</button>
|
||||
|
||||
<p v-if="error" class="text-red-600">{{ error }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
const config = useRuntimeConfig()
|
||||
const owners = await $fetch("/owners", {
|
||||
baseURL: config.public.apiBase
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-6">
|
||||
<h1 class="text-2xl font-bold mb-4">Owners</h1>
|
||||
|
||||
<ul class="space-y-2">
|
||||
<li v-for="o in owners" :key="o.id" class="p-3 bg-gray-100 rounded">
|
||||
{{ o.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
97
frontend/app/pages/owners/index.vue
Normal file
97
frontend/app/pages/owners/index.vue
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, onMounted } from "vue"
|
||||
|
||||
const { loadToken } = useAuth()
|
||||
const { apiFetch } = useApi()
|
||||
|
||||
const owners = ref([])
|
||||
const newOwnerName = ref("")
|
||||
const loading = ref(false)
|
||||
const error = ref("")
|
||||
|
||||
async function loadOwners() {
|
||||
loading.value = true
|
||||
try {
|
||||
owners.value = await apiFetch("/owners")
|
||||
} catch (e: any) {
|
||||
error.value = e.message
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function createOwner() {
|
||||
if (!newOwnerName.value.trim()) return
|
||||
|
||||
try {
|
||||
const owner = await apiFetch("/owners", {
|
||||
method: "POST",
|
||||
body: {
|
||||
name: newOwnerName.value
|
||||
}
|
||||
})
|
||||
|
||||
owners.value.push(owner)
|
||||
newOwnerName.value = ""
|
||||
} catch (e: any) {
|
||||
error.value = e.message
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadToken()
|
||||
loadOwners()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="space-y-6">
|
||||
<h1 class="text-3xl font-bold">Owner Verwaltung</h1>
|
||||
|
||||
<div class="p-4 bg-white shadow rounded space-y-4">
|
||||
<h2 class="text-xl font-semibold">Neuen Owner anlegen</h2>
|
||||
|
||||
<div class="flex gap-4">
|
||||
<input
|
||||
v-model="newOwnerName"
|
||||
type="text"
|
||||
placeholder="Owner Name"
|
||||
class="border p-2 rounded flex-1"
|
||||
/>
|
||||
|
||||
<button
|
||||
@click="createOwner"
|
||||
class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
|
||||
>
|
||||
Speichern
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 bg-white shadow rounded">
|
||||
<h2 class="text-xl font-semibold mb-4">Owner Liste</h2>
|
||||
|
||||
<div v-if="loading">Lade Owner…</div>
|
||||
<div v-if="error" class="text-red-600">{{ error }}</div>
|
||||
|
||||
<table class="w-full border-collapse">
|
||||
<thead>
|
||||
<tr class="border-b">
|
||||
<th class="text-left p-2">ID</th>
|
||||
<th class="text-left p-2">Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="owner in owners"
|
||||
:key="owner.id"
|
||||
class="border-b hover:bg-gray-50"
|
||||
>
|
||||
<td class="p-2">{{ owner.id }}</td>
|
||||
<td class="p-2">{{ owner.name }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Loading…
Add table
Add a link
Reference in a new issue