From 124f894f4e08fd63eae8c7a85babbc19f2cc1829 Mon Sep 17 00:00:00 2001
From: 潘志宝 <979469083@qq.com>
Date: 星期五, 13 六月 2025 09:39:36 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 src/views/ai/image/index/components/ImageCard.vue |  162 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 162 insertions(+), 0 deletions(-)

diff --git a/src/views/ai/image/index/components/ImageCard.vue b/src/views/ai/image/index/components/ImageCard.vue
new file mode 100644
index 0000000..4ba78ca
--- /dev/null
+++ b/src/views/ai/image/index/components/ImageCard.vue
@@ -0,0 +1,162 @@
+<template>
+  <el-card body-class="" class="image-card">
+    <div class="image-operation">
+      <div>
+        <el-button type="primary" text bg v-if="detail?.status === AiImageStatusEnum.IN_PROGRESS">
+          生成中
+        </el-button>
+        <el-button text bg v-else-if="detail?.status === AiImageStatusEnum.SUCCESS">
+          已完成
+        </el-button>
+        <el-button type="danger" text bg v-else-if="detail?.status === AiImageStatusEnum.FAIL">
+          异常
+        </el-button>
+      </div>
+      <!-- 操作区 -->
+      <div>
+        <el-button
+          class="btn"
+          text
+          :icon="Download"
+          @click="handleButtonClick('download', detail)"
+        />
+        <el-button
+          class="btn"
+          text
+          :icon="RefreshRight"
+          @click="handleButtonClick('regeneration', detail)"
+        />
+        <el-button class="btn" text :icon="Delete" @click="handleButtonClick('delete', detail)" />
+        <el-button class="btn" text :icon="More" @click="handleButtonClick('more', detail)" />
+      </div>
+    </div>
+    <div class="image-wrapper" ref="cardImageRef">
+      <el-image
+        class="image"
+        :src="detail?.picUrl"
+        :preview-src-list="[detail.picUrl]"
+        preview-teleported
+      />
+      <div v-if="detail?.status === AiImageStatusEnum.FAIL">
+        {{ detail?.errorMessage }}
+      </div>
+    </div>
+    <!-- Midjourney 专属操作 -->
+    <div class="image-mj-btns">
+      <el-button
+        size="small"
+        v-for="button in detail?.buttons"
+        :key="button"
+        class="min-w-40px ml-0 mr-10px mt-5px"
+        @click="handleMidjourneyBtnClick(button)"
+      >
+        {{ button.label }}{{ button.emoji }}
+      </el-button>
+    </div>
+  </el-card>
+</template>
+<script setup lang="ts">
+import { Delete, Download, More, RefreshRight } from '@element-plus/icons-vue'
+import { ImageVO, ImageMidjourneyButtonsVO } from '@/api/ai/image'
+import { PropType } from 'vue'
+import { ElLoading, LoadingOptionsResolved } from 'element-plus'
+import { AiImageStatusEnum } from '@/views/ai/utils/constants'
+
+const message = useMessage() // 消息
+
+const props = defineProps({
+  detail: {
+    type: Object as PropType<ImageVO>,
+    require: true
+  }
+})
+
+const cardImageRef = ref<any>() // 卡片 image ref
+const cardImageLoadingInstance = ref<any>() // 卡片 image ref
+
+/** 处理点击事件  */
+const handleButtonClick = async (type, detail: ImageVO) => {
+  emits('onBtnClick', type, detail)
+}
+
+/** 处理 Midjourney 按钮点击事件  */
+const handleMidjourneyBtnClick = async (button: ImageMidjourneyButtonsVO) => {
+  // 确认窗体
+  await message.confirm(`确认操作 "${button.label} ${button.emoji}" ?`)
+  emits('onMjBtnClick', button, props.detail)
+}
+
+const emits = defineEmits(['onBtnClick', 'onMjBtnClick']) // emits
+
+/** 监听详情 */
+const { detail } = toRefs(props)
+watch(detail, async (newVal, oldVal) => {
+  await handleLoading(newVal.status as string)
+})
+
+/** 处理加载状态 */
+const handleLoading = async (status: number) => {
+  // 情况一:如果是生成中,则设置加载中的 loading
+  if (status === AiImageStatusEnum.IN_PROGRESS) {
+    cardImageLoadingInstance.value = ElLoading.service({
+      target: cardImageRef.value,
+      text: '生成中...'
+    } as LoadingOptionsResolved)
+    // 情况二:如果已经生成结束,则移除 loading
+  } else {
+    if (cardImageLoadingInstance.value) {
+      cardImageLoadingInstance.value.close()
+      cardImageLoadingInstance.value = null
+    }
+  }
+}
+
+/** 初始化 */
+onMounted(async () => {
+  await handleLoading(props.detail.status as string)
+})
+</script>
+
+<style scoped lang="scss">
+.image-card {
+  width: 320px;
+  height: auto;
+  border-radius: 10px;
+  position: relative;
+  display: flex;
+  flex-direction: column;
+
+  .image-operation {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+
+    .btn {
+      //border: 1px solid red;
+      padding: 10px;
+      margin: 0;
+    }
+  }
+
+  .image-wrapper {
+    overflow: hidden;
+    margin-top: 20px;
+    height: 280px;
+    flex: 1;
+
+    .image {
+      width: 100%;
+      border-radius: 10px;
+    }
+  }
+
+  .image-mj-btns {
+    margin-top: 5px;
+    width: 100%;
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+    justify-content: flex-start;
+  }
+}
+</style>

--
Gitblit v1.9.3