ImageTaskCard.vue 3.9 KB

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