gaoluyang
2026-06-29 27cd042df9aca0383a49f3514bc21958dd890912
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<script setup lang="ts">
import type { PropType } from 'vue';
 
import type { AiImageApi } from '#/api/ai/image';
 
import { onMounted, ref, toRefs, watch } from 'vue';
 
import { confirm } from '../../../../../packages/effects/common-ui/src';
import { AiImageStatusEnum } from '../../../../../packages/constants/src';
import { IconifyIcon } from '../../../../../packages/icons/src';
 
import { Button, Card, Image, message } from 'ant-design-vue';
 
const props = defineProps({
  detail: {
    type: Object as PropType<AiImageApi.Image>,
    default: () => ({}),
  },
});
const emits = defineEmits(['onBtnClick', 'onMjBtnClick']);
 
/** 处理点击事件  */
async function handleButtonClick(type: string) {
  emits('onBtnClick', type, props.detail);
}
 
/** 处理 Midjourney 按钮点击事件  */
async function handleMidjourneyBtnClick(
  button: AiImageApi.ImageMidjourneyButtons,
) {
  await confirm(`确认操作 "${button.label} ${button.emoji}" ?`);
  emits('onMjBtnClick', button, props.detail);
}
 
/** 监听详情 */
const { detail } = toRefs(props);
watch(detail, async (newVal) => {
  await handleLoading(newVal.status);
});
const loading = ref();
 
/** 处理加载状态 */
async function handleLoading(status: number) {
  // 情况一:如果是生成中,则设置加载中的 loading
  if (status === AiImageStatusEnum.IN_PROGRESS) {
    loading.value = message.loading({
      content: `生成中...`,
    });
  } else {
    // 情况二:如果已经生成结束,则移除 loading
    if (loading.value) {
      setTimeout(loading.value, 100);
    }
  }
}
 
/** 初始化 */
onMounted(async () => {
  await handleLoading(props.detail.status);
});
</script>
<template>
  <Card class="relative flex h-auto w-80 flex-col rounded-lg">
    <!-- 图片操作区 -->
    <div class="flex flex-row justify-between">
      <div>
        <Button v-if="detail?.status === AiImageStatusEnum.IN_PROGRESS">
          生成中
        </Button>
        <Button v-else-if="detail?.status === AiImageStatusEnum.SUCCESS">
          已完成
        </Button>
        <Button danger v-else-if="detail?.status === AiImageStatusEnum.FAIL">
          异常
        </Button>
      </div>
      <div class="flex">
        <!-- TODO @AI:居右对齐 -->
        <Button
          class="m-0 p-2"
          type="text"
          @click="handleButtonClick('download')"
        >
          <IconifyIcon icon="lucide:download" />
        </Button>
        <Button
          class="m-0 p-2"
          type="text"
          @click="handleButtonClick('regeneration')"
        >
          <IconifyIcon icon="lucide:refresh-cw" />
        </Button>
        <Button
          class="m-0 p-2"
          type="text"
          @click="handleButtonClick('delete')"
        >
          <IconifyIcon icon="lucide:trash" />
        </Button>
        <Button
          class="m-0 p-2"
          type="text"
          @click="handleButtonClick('more')"
        >
          <IconifyIcon icon="lucide:ellipsis-vertical" />
        </Button>
      </div>
    </div>
 
    <!-- 图片展示区域 -->
    <div class="mt-5 h-72 flex-1 overflow-hidden">
      <Image class="w-full rounded-lg" :src="detail?.picUrl" />
      <div v-if="detail?.status === AiImageStatusEnum.FAIL">
        {{ detail?.errorMessage }}
      </div>
    </div>
 
    <!-- Midjourney 专属操作按钮 -->
    <div class="mt-2 flex w-full flex-wrap justify-start">
      <Button
        size="small"
        v-for="button in detail?.buttons"
        :key="button.customId"
        class="m-2 ml-0 min-w-10"
        @click="handleMidjourneyBtnClick(button)"
      >
        {{ button.label }}{{ button.emoji }}
      </Button>
    </div>
  </Card>
</template>