2024-05-26 20:47:29 +08:00
|
|
|
|
<template>
|
|
|
|
|
<el-card class="dr-task" body-class="task-card" shadow="never">
|
|
|
|
|
<template #header>绘画任务</template>
|
2024-06-19 10:41:33 +08:00
|
|
|
|
<div class="task-image-list" ref="imageTaskRef">
|
2024-06-18 14:31:14 +08:00
|
|
|
|
<ImageTaskCard
|
|
|
|
|
v-for="image in imageList"
|
|
|
|
|
:key="image"
|
|
|
|
|
:image-detail="image"
|
|
|
|
|
|
|
|
|
|
@on-btn-click="handlerImageBtnClick"
|
|
|
|
|
@on-mj-btn-click="handlerImageMjBtnClick"/>
|
|
|
|
|
</div>
|
2024-06-19 10:41:33 +08:00
|
|
|
|
<div class="task-image-pagination">
|
|
|
|
|
<el-pagination background layout="prev, pager, next"
|
|
|
|
|
:default-page-size="pageSize"
|
|
|
|
|
:total="pageTotal"
|
|
|
|
|
@change="handlerPageChange"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2024-05-26 20:47:29 +08:00
|
|
|
|
</el-card>
|
2024-05-26 20:59:42 +08:00
|
|
|
|
<!-- 图片 detail 抽屉 -->
|
|
|
|
|
<ImageDetailDrawer
|
2024-05-28 14:29:46 +08:00
|
|
|
|
:show="isShowImageDetail"
|
|
|
|
|
:id="showImageDetailId"
|
2024-05-26 20:59:42 +08:00
|
|
|
|
@handler-drawer-close="handlerDrawerClose"
|
|
|
|
|
/>
|
2024-05-26 20:47:29 +08:00
|
|
|
|
</template>
|
|
|
|
|
<script setup lang="ts">
|
2024-06-05 16:41:21 +08:00
|
|
|
|
import {ImageApi, ImageDetailVO, ImageMjActionVO, ImageMjButtonsVO} from '@/api/ai/image';
|
2024-05-26 20:59:42 +08:00
|
|
|
|
import ImageDetailDrawer from './ImageDetailDrawer.vue'
|
2024-05-26 21:51:42 +08:00
|
|
|
|
import ImageTaskCard from './ImageTaskCard.vue'
|
2024-06-18 14:35:42 +08:00
|
|
|
|
import {ElLoading} from "element-plus";
|
2024-05-26 20:59:42 +08:00
|
|
|
|
|
2024-05-28 10:37:44 +08:00
|
|
|
|
const message = useMessage() // 消息弹窗
|
|
|
|
|
|
2024-05-26 21:51:42 +08:00
|
|
|
|
const imageList = ref<ImageDetailVO[]>([]) // image 列表
|
2024-05-28 09:51:58 +08:00
|
|
|
|
const imageListInterval = ref<any>() // image 列表定时器,刷新列表
|
2024-06-01 16:49:42 +08:00
|
|
|
|
const isShowImageDetail = ref<boolean>(false) // 是否显示 task 详情
|
2024-05-28 14:29:46 +08:00
|
|
|
|
const showImageDetailId = ref<number>(0) // 是否显示 task 详情
|
2024-06-18 14:31:14 +08:00
|
|
|
|
const imageTaskRef = ref<any>() // ref
|
2024-06-18 14:35:42 +08:00
|
|
|
|
const imageTaskLoadingInstance = ref<any>() // loading
|
2024-06-18 14:31:14 +08:00
|
|
|
|
const imageTaskLoading = ref<boolean>(false) // loading
|
|
|
|
|
const pageNo = ref<number>(1) // page no
|
2024-06-19 10:41:33 +08:00
|
|
|
|
const pageSize = ref<number>(10) // page size
|
|
|
|
|
const pageTotal = ref<number>(0) // page size
|
2024-05-26 20:59:42 +08:00
|
|
|
|
|
2024-06-03 10:16:56 +08:00
|
|
|
|
/** 抽屉 - close */
|
2024-05-26 20:59:42 +08:00
|
|
|
|
const handlerDrawerClose = async () => {
|
2024-05-28 14:29:46 +08:00
|
|
|
|
isShowImageDetail.value = false
|
2024-05-26 20:59:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-03 10:16:56 +08:00
|
|
|
|
/** 任务 - detail */
|
2024-05-26 21:51:42 +08:00
|
|
|
|
const handlerDrawerOpen = async () => {
|
2024-05-28 14:29:46 +08:00
|
|
|
|
isShowImageDetail.value = true
|
2024-05-26 21:51:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取 - image 列表
|
|
|
|
|
*/
|
2024-06-19 10:41:33 +08:00
|
|
|
|
const getImageList = async (apply:boolean = false) => {
|
2024-06-18 14:31:14 +08:00
|
|
|
|
imageTaskLoading.value = true
|
|
|
|
|
try {
|
2024-06-18 14:35:42 +08:00
|
|
|
|
imageTaskLoadingInstance.value = ElLoading.service({
|
|
|
|
|
target: imageTaskRef.value,
|
|
|
|
|
text: '加载中...'
|
|
|
|
|
})
|
2024-06-19 10:41:33 +08:00
|
|
|
|
const { list, total } = await ImageApi.getImageList({pageNo: pageNo.value, pageSize: pageSize.value})
|
|
|
|
|
if (apply) {
|
|
|
|
|
imageList.value = [...imageList.value, ...list]
|
|
|
|
|
} else {
|
|
|
|
|
imageList.value = list
|
|
|
|
|
}
|
|
|
|
|
pageTotal.value = total
|
2024-06-18 14:31:14 +08:00
|
|
|
|
} finally {
|
2024-06-18 14:35:42 +08:00
|
|
|
|
if (imageTaskLoadingInstance.value) {
|
|
|
|
|
imageTaskLoadingInstance.value.close();
|
|
|
|
|
imageTaskLoadingInstance.value = null;
|
|
|
|
|
}
|
2024-06-18 14:31:14 +08:00
|
|
|
|
}
|
2024-05-26 21:51:42 +08:00
|
|
|
|
}
|
2024-05-26 20:59:42 +08:00
|
|
|
|
|
2024-06-03 10:16:56 +08:00
|
|
|
|
/** 图片 - btn click */
|
2024-05-26 21:56:10 +08:00
|
|
|
|
const handlerImageBtnClick = async (type, imageDetail: ImageDetailVO) => {
|
2024-05-28 14:29:46 +08:00
|
|
|
|
// 获取 image detail id
|
|
|
|
|
showImageDetailId.value = imageDetail.id
|
2024-06-18 16:58:23 +08:00
|
|
|
|
console.log('type', imageDetail.id)
|
2024-05-28 14:29:46 +08:00
|
|
|
|
// 处理不用 btn
|
2024-05-26 21:56:10 +08:00
|
|
|
|
if (type === 'more') {
|
|
|
|
|
await handlerDrawerOpen()
|
2024-05-28 10:37:44 +08:00
|
|
|
|
} else if (type === 'delete') {
|
|
|
|
|
await message.confirm(`是否删除照片?`)
|
|
|
|
|
await ImageApi.deleteImage(imageDetail.id)
|
|
|
|
|
await getImageList()
|
|
|
|
|
await message.success("删除成功!")
|
2024-05-28 11:35:02 +08:00
|
|
|
|
} else if (type === 'download') {
|
2024-05-28 14:29:46 +08:00
|
|
|
|
await downloadImage(imageDetail.picUrl)
|
2024-05-26 21:56:10 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-05-28 11:35:02 +08:00
|
|
|
|
|
2024-06-04 17:38:07 +08:00
|
|
|
|
/** 图片 - mj btn click */
|
2024-06-05 09:51:33 +08:00
|
|
|
|
const handlerImageMjBtnClick = async (button: ImageMjButtonsVO, imageDetail: ImageDetailVO) => {
|
2024-06-05 16:41:21 +08:00
|
|
|
|
// 1、构建 params 参数
|
|
|
|
|
const params = {
|
|
|
|
|
id: imageDetail.id,
|
|
|
|
|
customId: button.customId,
|
|
|
|
|
} as ImageMjActionVO
|
|
|
|
|
// 2、发送 action
|
|
|
|
|
await ImageApi.midjourneyAction(params)
|
|
|
|
|
// 3、刷新列表
|
|
|
|
|
await getImageList()
|
2024-06-04 17:38:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-03 10:16:56 +08:00
|
|
|
|
/** 下载 - image */
|
2024-06-01 16:49:42 +08:00
|
|
|
|
// TODO @fan:貌似可以考虑抽到 download 里面,作为一个方法
|
2024-05-28 11:35:02 +08:00
|
|
|
|
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
|
2024-06-05 13:57:02 +08:00
|
|
|
|
const ctx = canvas.getContext('2d') as CanvasDrawImage
|
2024-05-28 11:35:02 +08:00
|
|
|
|
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()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-19 10:41:33 +08:00
|
|
|
|
// page change
|
|
|
|
|
const handlerPageChange = async (page) => {
|
|
|
|
|
pageNo.value = page
|
|
|
|
|
await getImageList(false)
|
2024-06-18 14:31:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-05 13:54:36 +08:00
|
|
|
|
/** 暴露组件方法 */
|
2024-05-27 17:35:18 +08:00
|
|
|
|
defineExpose({getImageList})
|
2024-06-05 13:54:36 +08:00
|
|
|
|
|
|
|
|
|
/** 组件挂在的时候 */
|
2024-05-26 21:51:42 +08:00
|
|
|
|
onMounted(async () => {
|
2024-05-28 09:51:58 +08:00
|
|
|
|
// 获取 image 列表
|
2024-05-26 21:51:42 +08:00
|
|
|
|
await getImageList()
|
2024-05-28 09:51:58 +08:00
|
|
|
|
// 自动刷新 image 列表
|
|
|
|
|
imageListInterval.value = setInterval(async () => {
|
2024-06-19 10:41:33 +08:00
|
|
|
|
await getImageList(false)
|
2024-05-30 16:12:42 +08:00
|
|
|
|
}, 1000 * 20)
|
2024-05-28 09:51:58 +08:00
|
|
|
|
})
|
|
|
|
|
|
2024-06-05 13:54:36 +08:00
|
|
|
|
/** 组件取消挂在的时候 */
|
|
|
|
|
onUnmounted(async () => {
|
|
|
|
|
if (imageListInterval.value) {
|
|
|
|
|
clearInterval(imageListInterval.value)
|
|
|
|
|
}
|
2024-05-26 21:51:42 +08:00
|
|
|
|
})
|
2024-05-26 20:47:29 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
2024-05-27 17:20:03 +08:00
|
|
|
|
<style lang="scss">
|
|
|
|
|
.task-card {
|
2024-06-18 14:31:14 +08:00
|
|
|
|
margin: 0;
|
|
|
|
|
padding: 0;
|
|
|
|
|
height: 100%;
|
2024-06-18 14:53:51 +08:00
|
|
|
|
position: relative;
|
2024-06-18 14:31:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.task-image-list {
|
2024-06-18 14:53:51 +08:00
|
|
|
|
position: relative;
|
2024-05-27 17:20:03 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
flex-wrap: wrap;
|
2024-05-28 14:40:43 +08:00
|
|
|
|
align-content: flex-start;
|
2024-05-27 17:43:03 +08:00
|
|
|
|
height: 100%;
|
|
|
|
|
overflow: auto;
|
2024-06-18 14:31:14 +08:00
|
|
|
|
padding: 20px;
|
2024-06-19 10:41:33 +08:00
|
|
|
|
padding-bottom: 140px;
|
2024-06-18 14:53:51 +08:00
|
|
|
|
box-sizing: border-box; /* 确保内边距不会增加高度 */
|
2024-05-27 17:20:03 +08:00
|
|
|
|
|
|
|
|
|
>div {
|
|
|
|
|
margin-right: 20px;
|
2024-05-27 17:35:18 +08:00
|
|
|
|
margin-bottom: 20px;
|
2024-05-27 17:20:03 +08:00
|
|
|
|
}
|
2024-06-18 14:53:51 +08:00
|
|
|
|
>div:last-of-type {
|
|
|
|
|
//margin-bottom: 100px;
|
|
|
|
|
}
|
2024-05-27 17:20:03 +08:00
|
|
|
|
}
|
2024-06-19 10:41:33 +08:00
|
|
|
|
|
|
|
|
|
.task-image-pagination {
|
|
|
|
|
position: absolute;
|
|
|
|
|
bottom: 60px;
|
|
|
|
|
height: 50px;
|
|
|
|
|
line-height: 90px;
|
|
|
|
|
width: 100%;
|
|
|
|
|
z-index: 999;
|
|
|
|
|
background-color: #ffffff;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-27 17:20:03 +08:00
|
|
|
|
</style>
|
2024-05-26 20:47:29 +08:00
|
|
|
|
|
2024-05-27 17:20:03 +08:00
|
|
|
|
<style scoped lang="scss">
|
2024-05-26 20:47:29 +08:00
|
|
|
|
.dr-task {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
</style>
|