ImageTaskCard.vue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. <template>
  2. <el-card body-class="" class="image-card">
  3. <div class="image-operation">
  4. <div>
  5. <el-button type="primary" text bg v-if="imageDetail?.status === 10">生成中</el-button>
  6. <el-button text bg v-else-if="imageDetail?.status === 20">已完成</el-button>
  7. <el-button type="danger" text bg v-else-if="imageDetail?.status === 30">异常</el-button>
  8. </div>
  9. <!-- TODO @fan:1)按钮要不调整成详情、下载、再次生成、删除?;2)如果是再次生成,就把当前的参数填写到左侧的框框里? -->
  10. <div>
  11. <el-button
  12. class="btn"
  13. text
  14. :icon="Download"
  15. @click="handlerBtnClick('download', imageDetail)"
  16. />
  17. <el-button
  18. class="btn"
  19. text
  20. :icon="Delete"
  21. @click="handlerBtnClick('delete', imageDetail)"
  22. />
  23. <el-button class="btn" text :icon="More" @click="handlerBtnClick('more', imageDetail)" />
  24. </div>
  25. </div>
  26. <div class="image-wrapper" ref="cardImageRef">
  27. <!-- TODO @fan:要不加个点击,大图预览? -->
  28. <img class="image" :src="imageDetail?.picUrl" />
  29. <div v-if="imageDetail?.status === 30">{{ imageDetail?.errorMessage }}</div>
  30. </div>
  31. <!-- TODO @fan:style 使用 unocss 替代下 -->
  32. <div class="image-mj-btns">
  33. <el-button
  34. size="small"
  35. v-for="button in imageDetail?.buttons"
  36. :key="button"
  37. style="min-width: 40px; margin-left: 0; margin-right: 10px; margin-top: 5px"
  38. @click="handlerMjBtnClick(button)"
  39. >
  40. {{ button.label }}{{ button.emoji }}
  41. </el-button>
  42. </div>
  43. </el-card>
  44. </template>
  45. <script setup lang="ts">
  46. import { Delete, Download, More } from '@element-plus/icons-vue'
  47. import { ImageVO, ImageMjButtonsVO } from '@/api/ai/image'
  48. import { PropType } from 'vue'
  49. import { ElLoading, ElMessageBox } from 'element-plus'
  50. const cardImageRef = ref<any>() // 卡片 image ref
  51. const cardImageLoadingInstance = ref<any>() // 卡片 image ref
  52. const message = useMessage()
  53. const props = defineProps({
  54. imageDetail: {
  55. type: Object as PropType<ImageVO>,
  56. require: true
  57. }
  58. })
  59. /** 按钮 - 点击事件 */
  60. const handlerBtnClick = async (type, imageDetail: ImageVO) => {
  61. emits('onBtnClick', type, imageDetail)
  62. }
  63. const handlerLoading = async (status: number) => {
  64. // TODO @fan:这个搞成 Loading 组件,然后通过数据驱动,这样搞可以哇?
  65. if (status === 10) {
  66. cardImageLoadingInstance.value = ElLoading.service({
  67. target: cardImageRef.value,
  68. text: '生成中...'
  69. })
  70. } else {
  71. if (cardImageLoadingInstance.value) {
  72. cardImageLoadingInstance.value.close()
  73. cardImageLoadingInstance.value = null
  74. }
  75. }
  76. }
  77. /** mj 按钮 click */
  78. const handlerMjBtnClick = async (button: ImageMjButtonsVO) => {
  79. // 确认窗体
  80. await message.confirm(`确认操作 "${button.label} ${button.emoji}" ?`)
  81. emits('onMjBtnClick', button, props.imageDetail)
  82. }
  83. // watch
  84. const { imageDetail } = toRefs(props)
  85. watch(imageDetail, async (newVal, oldVal) => {
  86. await handlerLoading(newVal.status as string)
  87. })
  88. // emits
  89. const emits = defineEmits(['onBtnClick', 'onMjBtnClick'])
  90. //
  91. onMounted(async () => {
  92. await handlerLoading(props.imageDetail.status as string)
  93. })
  94. </script>
  95. <style scoped lang="scss">
  96. .image-card {
  97. width: 320px;
  98. height: auto;
  99. border-radius: 10px;
  100. position: relative;
  101. display: flex;
  102. flex-direction: column;
  103. .image-operation {
  104. display: flex;
  105. flex-direction: row;
  106. justify-content: space-between;
  107. .btn {
  108. //border: 1px solid red;
  109. padding: 10px;
  110. margin: 0;
  111. }
  112. }
  113. .image-wrapper {
  114. overflow: hidden;
  115. margin-top: 20px;
  116. height: 280px;
  117. flex: 1;
  118. .image {
  119. width: 100%;
  120. border-radius: 10px;
  121. }
  122. }
  123. .image-mj-btns {
  124. margin-top: 5px;
  125. width: 100%;
  126. display: flex;
  127. flex-direction: row;
  128. flex-wrap: wrap;
  129. justify-content: flex-start;
  130. }
  131. }
  132. </style>