对比新文件 |
| | |
| | | <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> |