feat: publication management with cover images, PDFs, and fruit images (story #04)
Full CRUD for publications; link fruits to publications; upload per-fruit PDF descriptions and fruit images stored as BYTEA; fruit detail page shows publication descriptions and images. ImageOverlayDrawer for cover thumbnail full-size view. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,8 @@ import { useRouter } from 'vue-router'
|
||||
import { useFruitStore } from '../stores/fruitStore'
|
||||
import { addImage, deleteImage, FRUIT_TYPES } from '../api/fruits'
|
||||
import type { Fruit } from '../api/fruits'
|
||||
import { getFruitDescriptions, getFruitPublicationImages } from '../api/publications'
|
||||
import type { PublicationDescription, PublicationFruitImage } from '../api/publications'
|
||||
|
||||
const props = defineProps<{ id: string }>()
|
||||
const router = useRouter()
|
||||
@@ -26,9 +28,19 @@ const imageTitle = ref('')
|
||||
const uploading = ref(false)
|
||||
const uploadError = ref<string | null>(null)
|
||||
|
||||
const pubDescriptions = ref<PublicationDescription[]>([])
|
||||
const pubFruitImages = ref<PublicationFruitImage[]>([])
|
||||
|
||||
onMounted(async () => {
|
||||
await store.fetchFruit(Number(props.id))
|
||||
if (store.current) startEdit(store.current)
|
||||
const id = Number(props.id)
|
||||
const [descs, imgs] = await Promise.all([
|
||||
getFruitDescriptions(id),
|
||||
getFruitPublicationImages(id),
|
||||
])
|
||||
pubDescriptions.value = descs
|
||||
pubFruitImages.value = imgs
|
||||
})
|
||||
|
||||
function startEdit(f: Fruit) {
|
||||
@@ -258,6 +270,35 @@ async function removeImage(imageId: number) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Publication descriptions -->
|
||||
<div v-if="pubDescriptions.length > 0" class="mt-8">
|
||||
<h2 class="text-lg font-semibold text-gray-800 mb-3">Beschreibungen in Publikationen</h2>
|
||||
<ul class="space-y-1">
|
||||
<li v-for="d in pubDescriptions" :key="d.id">
|
||||
<a
|
||||
:href="d.url"
|
||||
target="_blank"
|
||||
class="text-blue-600 hover:underline text-sm"
|
||||
>
|
||||
{{ d.publication_title }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Publication fruit images -->
|
||||
<div v-if="pubFruitImages.length > 0" class="mt-8">
|
||||
<h2 class="text-lg font-semibold text-gray-800 mb-3">Bilder aus Publikationen</h2>
|
||||
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
|
||||
<div v-for="img in pubFruitImages" :key="img.id" class="border rounded overflow-hidden">
|
||||
<img :src="img.url" :alt="img.filename ?? 'Fruchtbild'" class="w-full h-32 object-cover" />
|
||||
<div class="p-1 text-xs text-gray-500">
|
||||
{{ img.publication_title }}{{ img.publication_author ? ' · ' + img.publication_author : '' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6">
|
||||
<RouterLink to="/fruits" class="text-green-700 hover:underline text-sm">← Zurück zur Liste</RouterLink>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user