190 lines
5.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-card class="dr-task" body-class="task-card" shadow="never">
<template #header>绘画任务</template>
<div class="task-image-list" ref="imageTaskRef" @scroll="handleTabsScroll">
<ImageTaskCard
v-for="image in imageList"
:key="image"
:image-detail="image"
@on-btn-click="handlerImageBtnClick"
@on-mj-btn-click="handlerImageMjBtnClick"/>
</div>
</el-card>
<!-- 图片 detail 抽屉 -->
<ImageDetailDrawer
:show="isShowImageDetail"
:id="showImageDetailId"
@handler-drawer-close="handlerDrawerClose"
/>
</template>
<script setup lang="ts">
import {ImageApi, ImageDetailVO, ImageMjActionVO, ImageMjButtonsVO} from '@/api/ai/image';
import ImageDetailDrawer from './ImageDetailDrawer.vue'
import ImageTaskCard from './ImageTaskCard.vue'
import {ElLoading} from "element-plus";
const message = useMessage() // 消息弹窗
const imageList = ref<ImageDetailVO[]>([]) // image 列表
const imageListInterval = ref<any>() // image 列表定时器,刷新列表
const isShowImageDetail = ref<boolean>(false) // 是否显示 task 详情
const showImageDetailId = ref<number>(0) // 是否显示 task 详情
const imageTaskRef = ref<any>() // ref
const imageTaskLoadingInstance = ref<any>() // loading
const imageTaskLoading = ref<boolean>(false) // loading
const pageNo = ref<number>(1) // page no
const pageSize = ref<number>(20) // page size
/** 抽屉 - close */
const handlerDrawerClose = async () => {
isShowImageDetail.value = false
}
/** 任务 - detail */
const handlerDrawerOpen = async () => {
isShowImageDetail.value = true
}
/**
* 获取 - image 列表
*/
const getImageList = async () => {
imageTaskLoading.value = true
try {
imageTaskLoadingInstance.value = ElLoading.service({
target: imageTaskRef.value,
text: '加载中...'
})
const { list } = await ImageApi.getImageList({pageNo: pageNo.value, pageSize: pageSize.value})
// imageList.value.push.apply(imageList.value, list)
imageList.value = list
} finally {
if (imageTaskLoadingInstance.value) {
imageTaskLoadingInstance.value.close();
imageTaskLoadingInstance.value = null;
}
}
}
/** 图片 - btn click */
const handlerImageBtnClick = async (type, imageDetail: ImageDetailVO) => {
// 获取 image detail id
showImageDetailId.value = imageDetail.id
console.log('type', imageDetail.id)
// 处理不用 btn
if (type === 'more') {
await handlerDrawerOpen()
} else if (type === 'delete') {
await message.confirm(`是否删除照片?`)
await ImageApi.deleteImage(imageDetail.id)
await getImageList()
await message.success("删除成功!")
} else if (type === 'download') {
await downloadImage(imageDetail.picUrl)
}
}
/** 图片 - mj btn click */
const handlerImageMjBtnClick = async (button: ImageMjButtonsVO, imageDetail: ImageDetailVO) => {
// 1、构建 params 参数
const params = {
id: imageDetail.id,
customId: button.customId,
} as ImageMjActionVO
// 2、发送 action
await ImageApi.midjourneyAction(params)
// 3、刷新列表
await getImageList()
}
/** 下载 - image */
// TODO @fan貌似可以考虑抽到 download 里面,作为一个方法
const downloadImage = async (imageUrl) => {
const image = new Image()
image.setAttribute('crossOrigin', 'anonymous')
image.src = imageUrl
image.onload = () => {
const canvas = document.createElement('canvas')
canvas.width = image.width
canvas.height = image.height
const ctx = canvas.getContext('2d') as CanvasDrawImage
ctx.drawImage(image, 0, 0, image.width, image.height)
const url = canvas.toDataURL('image/png')
const a = document.createElement('a')
a.href = url
a.download = 'image.png'
a.click()
}
}
const handleTabsScroll = async () => {
// todo 先不分页,只显示 top 前多少
// if (imageTaskRef.value) {
// const { scrollTop, scrollHeight, clientHeight } = imageTaskRef.value;
// if (scrollTop + clientHeight >= scrollHeight - 20 && !imageTaskLoading.value) {
// console.log('分页')
// pageNo.value = pageNo.value + 1
// await getImageList();
// }
// }
}
/** 暴露组件方法 */
defineExpose({getImageList})
/** 组件挂在的时候 */
onMounted(async () => {
// 获取 image 列表
await getImageList()
// 自动刷新 image 列表
imageListInterval.value = setInterval(async () => {
await getImageList()
}, 1000 * 20)
})
/** 组件取消挂在的时候 */
onUnmounted(async () => {
if (imageListInterval.value) {
clearInterval(imageListInterval.value)
}
})
</script>
<style lang="scss">
.task-card {
margin: 0;
padding: 0;
height: 100%;
position: relative;
}
.task-image-list {
position: relative;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-content: flex-start;
height: 100%;
overflow: auto;
padding: 20px;
padding-bottom: 100px;
box-sizing: border-box; /* 确保内边距不会增加高度 */
>div {
margin-right: 20px;
margin-bottom: 20px;
}
>div:last-of-type {
//margin-bottom: 100px;
}
}
</style>
<style scoped lang="scss">
.dr-task {
width: 100%;
height: 100%;
}
</style>