ソースを参照

图片新增查看大图

liuziting 6 ヶ月 前
コミット
7f74f967eb
3 ファイル変更48 行追加51 行削除
  1. 4 46
      src/components/ImageModal.vue
  2. 40 1
      src/components/RecipeCard.vue
  3. 4 4
      src/views/Gallery.vue

+ 4 - 46
src/components/ImageModal.vue

@@ -1,6 +1,6 @@
 <template>
-    <div class="fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-4" @click="$emit('close')">
-        <div class="bg-white rounded-lg border-2 border-[#0A0910] max-w-4xl max-h-[90vh] overflow-hidden" @click.stop>
+    <div class="fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-2 md:p-4" @click="$emit('close')">
+        <div class="bg-white rounded-lg border-2 border-[#0A0910] w-full max-w-4xl max-h-[95vh] md:max-h-[90vh] overflow-hidden" @click.stop>
             <!-- 头部 -->
             <div class="bg-blue-500 text-white p-4 flex items-center justify-between">
                 <div>
@@ -11,48 +11,8 @@
             </div>
 
             <!-- 图片 -->
-            <div class="relative">
-                <img :src="image.url" :alt="image.recipeName" class="w-full max-h-[60vh] object-contain" />
-            </div>
-
-            <!-- 详情信息 -->
-            <div class="p-4 max-h-48 overflow-y-auto">
-                <!-- 食材 -->
-                <div class="mb-4">
-                    <h4 class="font-bold text-gray-800 mb-2 flex items-center gap-1">🥬 食材</h4>
-                    <div class="flex flex-wrap gap-1">
-                        <span v-for="ingredient in image.ingredients" :key="ingredient" class="bg-yellow-100 text-yellow-800 px-2 py-1 rounded text-sm border">
-                            {{ ingredient }}
-                        </span>
-                    </div>
-                </div>
-
-                <!-- 生成提示词 -->
-                <div v-if="image.prompt" class="mb-4">
-                    <h4 class="font-bold text-gray-800 mb-2 flex items-center gap-1">🎨 生成提示</h4>
-                    <p class="text-gray-600 text-sm bg-gray-50 p-3 rounded border">
-                        {{ image.prompt }}
-                    </p>
-                </div>
-            </div>
-
-            <!-- 操作按钮 -->
-            <div class="bg-gray-50 border-t border-gray-200 p-4 flex items-center justify-between">
-                <div class="text-sm text-gray-500">生成于 {{ new Date(image.generatedAt).toLocaleString('zh-CN') }}</div>
-                <div class="flex items-center gap-2">
-                    <button
-                        @click="$emit('download', image)"
-                        class="px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded-lg text-sm font-medium border-2 border-[#0A0910] transition-all duration-200 hover:scale-105"
-                    >
-                        📥 下载
-                    </button>
-                    <button
-                        @click="$emit('delete', image.id)"
-                        class="px-4 py-2 bg-red-500 hover:bg-red-600 text-white rounded-lg text-sm font-medium border-2 border-[#0A0910] transition-all duration-200 hover:scale-105"
-                    >
-                        🗑️ 删除
-                    </button>
-                </div>
+            <div class="relative bg-black flex items-center justify-center min-h-[50vh] max-h-[80vh]">
+                <img :src="image.url" :alt="image.recipeName" class="max-w-full max-h-full object-contain" />
             </div>
         </div>
     </div>
@@ -69,8 +29,6 @@ defineProps<Props>()
 
 defineEmits<{
     close: []
-    delete: [imageId: string]
-    download: [image: GalleryImage]
 }>()
 
 // 格式化日期

+ 40 - 1
src/components/RecipeCard.vue

@@ -187,8 +187,9 @@
                     <img
                         :src="generatedImage.url"
                         :alt="`${recipe.name}效果图`"
-                        class="w-full h-[20rem] object-cover rounded-lg border-2 border-[#0A0910]"
+                        class="w-full h-[20rem] object-cover rounded-lg border-2 border-[#0A0910] cursor-pointer transition-all duration-300 hover:brightness-110 hover:scale-[1.02]"
                         @error="handleImageError"
+                        @click="openImageModal"
                     />
                 </div>
 
@@ -205,6 +206,13 @@
             </div>
         </div>
     </div>
+
+    <!-- 图片弹窗 -->
+    <ImageModal
+        v-if="showImageModal && generatedImage"
+        :image="getModalImageData()!"
+        @close="closeImageModal"
+    />
 </template>
 
 <script setup lang="ts">
@@ -212,9 +220,11 @@ import { computed, ref, onUnmounted } from 'vue'
 import type { Recipe } from '@/types'
 import { generateRecipeImage, type GeneratedImage } from '@/services/imageService'
 import { getNutritionAnalysis, getWinePairing } from '@/services/aiService'
+import type { GalleryImage } from '@/services/galleryService'
 import FavoriteButton from './FavoriteButton.vue'
 import NutritionAnalysis from './NutritionAnalysis.vue'
 import WinePairing from './WinePairing.vue'
+import ImageModal from './ImageModal.vue'
 
 interface Props {
     recipe: Recipe
@@ -239,6 +249,7 @@ const isFetchingNutrition = ref(false)
 const nutritionError = ref('')
 const isFetchingWine = ref(false)
 const wineError = ref('')
+const showImageModal = ref(false)
 
 // 图片生成加载文字轮播
 const imageLoadingTexts = [
@@ -406,6 +417,34 @@ const fetchWinePairing = async () => {
     }
 }
 
+// 打开图片弹窗
+const openImageModal = () => {
+    if (generatedImage.value) {
+        showImageModal.value = true
+    }
+}
+
+// 关闭图片弹窗
+const closeImageModal = () => {
+    showImageModal.value = false
+}
+
+// 创建适配ImageModal的图片数据
+const getModalImageData = (): GalleryImage | null => {
+    if (!generatedImage.value) return null
+    
+    return {
+        id: generatedImage.value.id,
+        url: generatedImage.value.url,
+        recipeName: props.recipe.name,
+        recipeId: props.recipe.id,
+        cuisine: props.recipe.cuisine,
+        ingredients: props.recipe.ingredients,
+        prompt: `一道精美的${props.recipe.cuisine.replace('大师', '').replace('菜', '')}菜肴:${props.recipe.name}`,
+        generatedAt: new Date().toISOString()
+    }
+}
+
 onUnmounted(() => {
     if (imageLoadingInterval) {
         clearInterval(imageLoadingInterval)

+ 4 - 4
src/views/Gallery.vue

@@ -80,7 +80,7 @@
                         class="bg-white border-2 border-[#0A0910] rounded-lg overflow-hidden hover:shadow-lg transition-all duration-200 group"
                     >
                         <!-- 图片 -->
-                        <div class="relative aspect-[4/3] overflow-hidden">
+                        <div class="relative aspect-[4/3] overflow-hidden cursor-pointer" @click="openImageModal(image)">
                             <img
                                 :src="image.url"
                                 :alt="image.recipeName"
@@ -90,10 +90,10 @@
 
                             <!-- 悬浮信息层 -->
                             <div
-                                class="absolute inset-0 bg-gradient-to-t from-black/80 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"
+                                class="absolute inset-0 bg-gradient-to-t from-black/80 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 pointer-events-none"
                             >
                                 <!-- 顶部操作按钮 -->
-                                <div class="absolute top-3 right-3 flex gap-2">
+                                <div class="absolute top-3 right-3 flex gap-2 pointer-events-auto">
                                     <button
                                         @click.stop="downloadImage(image)"
                                         class="p-2 bg-blue-500/80 hover:bg-blue-500 text-white rounded-full text-sm transition-colors backdrop-blur-sm"
@@ -171,7 +171,7 @@
         </div>
 
         <!-- 图片详情弹窗 -->
-        <ImageModal v-if="selectedImage" :image="selectedImage" @close="selectedImage = null" @delete="confirmDeleteImage" @download="downloadImage" />
+        <ImageModal v-if="selectedImage" :image="selectedImage" @close="selectedImage = null" />
 
         <!-- 删除确认弹窗 -->
         <ConfirmModal v-if="deletingImageId" title="确认删除图片" message="确定要删除这张图片吗?此操作不可恢复。" @confirm="deleteImage" @cancel="deletingImageId = null" />