houzhongjian
2024-08-08 820397e43a0b64d35c6d31d2a55475061438593b
提交 | 用户 | 时间
820397 1 <template>
H 2   <el-card body-class="" class="image-card">
3     <div class="image-operation">
4       <div>
5         <el-button type="primary" text bg v-if="detail?.status === AiImageStatusEnum.IN_PROGRESS">
6           生成中
7         </el-button>
8         <el-button text bg v-else-if="detail?.status === AiImageStatusEnum.SUCCESS">
9           已完成
10         </el-button>
11         <el-button type="danger" text bg v-else-if="detail?.status === AiImageStatusEnum.FAIL">
12           异常
13         </el-button>
14       </div>
15       <!-- 操作区 -->
16       <div>
17         <el-button
18           class="btn"
19           text
20           :icon="Download"
21           @click="handleButtonClick('download', detail)"
22         />
23         <el-button
24           class="btn"
25           text
26           :icon="RefreshRight"
27           @click="handleButtonClick('regeneration', detail)"
28         />
29         <el-button class="btn" text :icon="Delete" @click="handleButtonClick('delete', detail)" />
30         <el-button class="btn" text :icon="More" @click="handleButtonClick('more', detail)" />
31       </div>
32     </div>
33     <div class="image-wrapper" ref="cardImageRef">
34       <el-image
35         class="image"
36         :src="detail?.picUrl"
37         :preview-src-list="[detail.picUrl]"
38         preview-teleported
39       />
40       <div v-if="detail?.status === AiImageStatusEnum.FAIL">
41         {{ detail?.errorMessage }}
42       </div>
43     </div>
44     <!-- Midjourney 专属操作 -->
45     <div class="image-mj-btns">
46       <el-button
47         size="small"
48         v-for="button in detail?.buttons"
49         :key="button"
50         class="min-w-40px ml-0 mr-10px mt-5px"
51         @click="handleMidjourneyBtnClick(button)"
52       >
53         {{ button.label }}{{ button.emoji }}
54       </el-button>
55     </div>
56   </el-card>
57 </template>
58 <script setup lang="ts">
59 import { Delete, Download, More, RefreshRight } from '@element-plus/icons-vue'
60 import { ImageVO, ImageMidjourneyButtonsVO } from '@/api/ai/image'
61 import { PropType } from 'vue'
62 import { ElLoading, LoadingOptionsResolved } from 'element-plus'
63 import { AiImageStatusEnum } from '@/views/ai/utils/constants'
64
65 const message = useMessage() // 消息
66
67 const props = defineProps({
68   detail: {
69     type: Object as PropType<ImageVO>,
70     require: true
71   }
72 })
73
74 const cardImageRef = ref<any>() // 卡片 image ref
75 const cardImageLoadingInstance = ref<any>() // 卡片 image ref
76
77 /** 处理点击事件  */
78 const handleButtonClick = async (type, detail: ImageVO) => {
79   emits('onBtnClick', type, detail)
80 }
81
82 /** 处理 Midjourney 按钮点击事件  */
83 const handleMidjourneyBtnClick = async (button: ImageMidjourneyButtonsVO) => {
84   // 确认窗体
85   await message.confirm(`确认操作 "${button.label} ${button.emoji}" ?`)
86   emits('onMjBtnClick', button, props.detail)
87 }
88
89 const emits = defineEmits(['onBtnClick', 'onMjBtnClick']) // emits
90
91 /** 监听详情 */
92 const { detail } = toRefs(props)
93 watch(detail, async (newVal, oldVal) => {
94   await handleLoading(newVal.status as string)
95 })
96
97 /** 处理加载状态 */
98 const handleLoading = async (status: number) => {
99   // 情况一:如果是生成中,则设置加载中的 loading
100   if (status === AiImageStatusEnum.IN_PROGRESS) {
101     cardImageLoadingInstance.value = ElLoading.service({
102       target: cardImageRef.value,
103       text: '生成中...'
104     } as LoadingOptionsResolved)
105     // 情况二:如果已经生成结束,则移除 loading
106   } else {
107     if (cardImageLoadingInstance.value) {
108       cardImageLoadingInstance.value.close()
109       cardImageLoadingInstance.value = null
110     }
111   }
112 }
113
114 /** 初始化 */
115 onMounted(async () => {
116   await handleLoading(props.detail.status as string)
117 })
118 </script>
119
120 <style scoped lang="scss">
121 .image-card {
122   width: 320px;
123   height: auto;
124   border-radius: 10px;
125   position: relative;
126   display: flex;
127   flex-direction: column;
128
129   .image-operation {
130     display: flex;
131     flex-direction: row;
132     justify-content: space-between;
133
134     .btn {
135       //border: 1px solid red;
136       padding: 10px;
137       margin: 0;
138     }
139   }
140
141   .image-wrapper {
142     overflow: hidden;
143     margin-top: 20px;
144     height: 280px;
145     flex: 1;
146
147     .image {
148       width: 100%;
149       border-radius: 10px;
150     }
151   }
152
153   .image-mj-btns {
154     margin-top: 5px;
155     width: 100%;
156     display: flex;
157     flex-direction: row;
158     flex-wrap: wrap;
159     justify-content: flex-start;
160   }
161 }
162 </style>